Rubka 6.6.13__py3-none-any.whl → 6.7.1__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.
Potentially problematic release.
This version of Rubka might be problematic. Click here for more details.
- rubka/asynco.py +294 -139
- rubka/context.py +209 -12
- rubka/exceptions.py +35 -1
- rubka/update.py +209 -12
- {rubka-6.6.13.dist-info → rubka-6.7.1.dist-info}/METADATA +1 -1
- {rubka-6.6.13.dist-info → rubka-6.7.1.dist-info}/RECORD +9 -9
- {rubka-6.6.13.dist-info → rubka-6.7.1.dist-info}/WHEEL +0 -0
- {rubka-6.6.13.dist-info → rubka-6.7.1.dist-info}/entry_points.txt +0 -0
- {rubka-6.6.13.dist-info → rubka-6.7.1.dist-info}/top_level.txt +0 -0
rubka/asynco.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import asyncio,aiohttp,aiofiles,time,datetime,json,tempfile,os,sys,subprocess,mimetypes
|
|
1
|
+
import asyncio,aiohttp,aiofiles,time,datetime,json,tempfile,os,sys,subprocess,mimetypes,time, hashlib
|
|
2
2
|
from typing import List, Optional, Dict, Any, Literal, Callable, Union,Set
|
|
3
|
-
from
|
|
3
|
+
from collections import OrderedDict
|
|
4
|
+
from .exceptions import APIRequestError,raise_for_status,InvalidAccessError,InvalidInputError,TooRequestError,InvalidTokenError
|
|
4
5
|
from .adaptorrubka import Client as Client_get
|
|
5
6
|
from .logger import logger
|
|
6
7
|
from .rubino import Bot as Rubino
|
|
@@ -12,7 +13,7 @@ class FeatureNotAvailableError(Exception):
|
|
|
12
13
|
|
|
13
14
|
from tqdm.asyncio import tqdm
|
|
14
15
|
from urllib.parse import urlparse, parse_qs
|
|
15
|
-
|
|
16
|
+
|
|
16
17
|
from pathlib import Path
|
|
17
18
|
from tqdm import tqdm
|
|
18
19
|
API_URL = "https://botapi.rubika.ir/v3"
|
|
@@ -98,38 +99,64 @@ class AttrDict(dict):
|
|
|
98
99
|
|
|
99
100
|
class Robot:
|
|
100
101
|
"""
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
102
|
+
Main asynchronous class to interact with the Rubika Bot API.
|
|
103
|
+
|
|
104
|
+
This class handles sending and receiving messages, inline queries, callbacks,
|
|
105
|
+
and manages sessions and API interactions. It is initialized with a bot token
|
|
106
|
+
and provides multiple optional parameters for configuration.
|
|
107
|
+
|
|
108
|
+
Attributes:
|
|
109
|
+
token (str): Bot token used for authentication with Rubika Bot API.
|
|
110
|
+
session_name (str | None): Optional session name for storing session data.
|
|
111
|
+
auth (str | None): Optional authentication string for advanced features related to account key.
|
|
112
|
+
Key (str | None): Optional account key for additional authorization if required.
|
|
113
|
+
platform (str): Platform type, default is 'web'.
|
|
114
|
+
web_hook (str | None): Optional webhook URL for receiving updates.
|
|
115
|
+
timeout (int): Timeout for API requests in seconds (default 10).
|
|
116
|
+
show_progress (bool): Whether to show progress for long operations (default False).
|
|
117
|
+
raise_errors (bool): Whether to raise exceptions on API errors (default True).
|
|
118
|
+
proxy (str | None): Optional proxy URL to route requests through.
|
|
119
|
+
retries (int): Number of times to retry a failed API request (default 2).
|
|
120
|
+
retry_delay (float): Delay between retries in seconds (default 0.5).
|
|
121
|
+
user_agent (str | None): Custom User-Agent header for requests.
|
|
122
|
+
safeSendMode (bool): If True, messages are sent safely. If reply fails using message_id, sends without message_id (default False).
|
|
123
|
+
max_cache_size (int): Maximum number of processed messages stored to prevent duplicates (default 1000).
|
|
124
|
+
max_msg_age (int): Maximum age of messages in seconds to consider for processing (default 20).
|
|
125
|
+
|
|
126
|
+
Example:
|
|
127
|
+
```python
|
|
128
|
+
import asyncio
|
|
129
|
+
from rubka.asynco import Robot, filters, Message
|
|
130
|
+
|
|
131
|
+
bot = Robot(token="YOUR_BOT_TOKEN", safeSendMode=False, max_cache_size=1000)
|
|
132
|
+
|
|
133
|
+
@bot.on_message(filters.is_command.start)
|
|
134
|
+
async def start_command(bot: Robot, message: Message):
|
|
135
|
+
await message.reply("Hello!")
|
|
136
|
+
|
|
137
|
+
asyncio.run(bot.run())
|
|
138
|
+
```
|
|
139
|
+
Notes:
|
|
140
|
+
|
|
141
|
+
token is mandatory, all other parameters are optional.
|
|
142
|
+
|
|
143
|
+
safeSendMode ensures reliable message sending even if replying by message_id fails.
|
|
144
|
+
|
|
145
|
+
max_cache_size and max_msg_age help manage duplicate message processing efficiently.
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
def __init__(self, token: str, session_name: str = None, auth: str = None, Key: str = None, platform: str = "web", web_hook: str = None, timeout: int = 10, show_progress: bool = False, raise_errors: bool = True,proxy: str = None,retries: int = 2,retry_delay: float = 0.5,user_agent: str = None,safeSendMode = False,max_cache_size: int = 1000,max_msg_age : int = 60):
|
|
129
149
|
self.token = token
|
|
130
150
|
self._inline_query_handlers: List[dict] = []
|
|
131
151
|
self.timeout = timeout
|
|
132
152
|
self.auth = auth
|
|
153
|
+
self.safeSendMode = safeSendMode
|
|
154
|
+
self.user_agent = user_agent
|
|
155
|
+
self.proxy = proxy
|
|
156
|
+
self.max_msg_age = max_msg_age
|
|
157
|
+
self.retries = retries
|
|
158
|
+
self.retry_delay = retry_delay
|
|
159
|
+
self.raise_errors = raise_errors
|
|
133
160
|
self.show_progress = show_progress
|
|
134
161
|
self.session_name = session_name
|
|
135
162
|
self.Key = Key
|
|
@@ -139,20 +166,25 @@ class Robot:
|
|
|
139
166
|
self._aiohttp_session: aiohttp.ClientSession = None
|
|
140
167
|
self.sessions: Dict[str, Dict[str, Any]] = {}
|
|
141
168
|
self._callback_handler = None
|
|
142
|
-
self.
|
|
143
|
-
self.
|
|
169
|
+
self._processed_message_ids = OrderedDict()
|
|
170
|
+
self._max_cache_size = max_cache_size
|
|
171
|
+
|
|
172
|
+
self._connector = aiohttp.TCPConnector(limit=100, ssl=False)
|
|
144
173
|
|
|
145
174
|
self._callback_handlers: List[dict] = []
|
|
146
175
|
self._edited_message_handlers = []
|
|
147
|
-
self._processed_message_ids: Dict[str, float] = {}
|
|
148
176
|
self._message_handlers: List[dict] = []
|
|
149
177
|
|
|
150
178
|
logger.info(f"Initialized RubikaBot with token: {token[:8]}***")
|
|
151
179
|
async def _get_session(self) -> aiohttp.ClientSession:
|
|
152
|
-
"""Lazily creates and returns the aiohttp session."""
|
|
153
180
|
if self._aiohttp_session is None or self._aiohttp_session.closed:
|
|
154
|
-
|
|
181
|
+
connector = aiohttp.TCPConnector(limit=100, ssl=False) # limit اتصالات همزمان
|
|
182
|
+
timeout = aiohttp.ClientTimeout(total=self.timeout)
|
|
183
|
+
self._aiohttp_session = aiohttp.ClientSession(connector=connector, timeout=timeout)
|
|
155
184
|
return self._aiohttp_session
|
|
185
|
+
async def close(self):
|
|
186
|
+
if self._session and not self._session.closed:
|
|
187
|
+
await self._session.close()
|
|
156
188
|
|
|
157
189
|
async def _initialize_webhook(self):
|
|
158
190
|
"""Initializes and sets the webhook endpoint if provided."""
|
|
@@ -183,22 +215,43 @@ class Robot:
|
|
|
183
215
|
async def _post(self, method: str, data: Dict[str, Any]) -> Dict[str, Any]:
|
|
184
216
|
url = f"{API_URL}/{self.token}/{method}"
|
|
185
217
|
session = await self._get_session()
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
return AttrDict(json_resp)
|
|
198
|
-
except aiohttp.ClientError as e:
|
|
199
|
-
logger.error(f"API request failed: {e}")
|
|
200
|
-
raise APIRequestError(f"API request failed: {e}") from e
|
|
218
|
+
for attempt in range(1, self.retries + 1):
|
|
219
|
+
try:
|
|
220
|
+
headers = {}
|
|
221
|
+
if self.user_agent:headers["User-Agent"] = self.user_agent
|
|
222
|
+
async with session.post(url, json=data, proxy=self.proxy,headers=headers) as response:
|
|
223
|
+
if response.status in (429, 500, 502, 503, 504):
|
|
224
|
+
logger.warning(f"[{method}] Got status {response.status}, retry {attempt}/{self.retries}...")
|
|
225
|
+
if attempt < self.retries:
|
|
226
|
+
await asyncio.sleep(self.retry_delay)
|
|
227
|
+
continue
|
|
228
|
+
response.raise_for_status()
|
|
201
229
|
|
|
230
|
+
response.raise_for_status()
|
|
231
|
+
try:
|
|
232
|
+
json_resp = await response.json(content_type=None)
|
|
233
|
+
except Exception:
|
|
234
|
+
text_resp = await response.text()
|
|
235
|
+
logger.error(f"[{method}] Invalid JSON response: {text_resp}")
|
|
236
|
+
raise APIRequestError(f"Invalid JSON response: {text_resp}")
|
|
237
|
+
|
|
238
|
+
status = json_resp.get("status")
|
|
239
|
+
if status in {"INVALID_ACCESS", "INVALID_INPUT", "TOO_REQUESTS"}:
|
|
240
|
+
if self.raise_errors:
|
|
241
|
+
raise_for_status(json_resp)
|
|
242
|
+
return AttrDict(json_resp)
|
|
243
|
+
return AttrDict({**json_resp, **data,"message_id":json_resp.get("data").get("message_id")})
|
|
244
|
+
|
|
245
|
+
except (aiohttp.ClientError, asyncio.TimeoutError) as e:
|
|
246
|
+
logger.warning(f"[{method}] Attempt {attempt}/{self.retries} failed: {e}")
|
|
247
|
+
if attempt < self.retries:
|
|
248
|
+
await asyncio.sleep(self.retry_delay)
|
|
249
|
+
continue
|
|
250
|
+
logger.error(f"[{method}] API request failed after {self.retries} retries: {e}")
|
|
251
|
+
raise APIRequestError(f"API request failed: {e}") from e
|
|
252
|
+
def _make_dup_key(self, message_id: str, update_type: str, msg_data: dict) -> str:
|
|
253
|
+
raw = f"{message_id}:{update_type}:{msg_data.get('text','')}:{msg_data.get('author_guid','')}"
|
|
254
|
+
return hashlib.sha1(raw.encode()).hexdigest()
|
|
202
255
|
async def get_me(self) -> Dict[str, Any]:
|
|
203
256
|
"""Get info about the bot itself."""
|
|
204
257
|
return await self._post("getMe", {})
|
|
@@ -504,25 +557,34 @@ class Robot:
|
|
|
504
557
|
return wrapper
|
|
505
558
|
return decorator
|
|
506
559
|
def on_message(
|
|
507
|
-
self,
|
|
508
|
-
filters: Optional[Callable[[Message], bool]] = None,
|
|
509
|
-
commands: Optional[List[str]] = None
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
560
|
+
self,
|
|
561
|
+
filters: Optional[Callable[[Message], bool]] = None,
|
|
562
|
+
commands: Optional[List[str]] = None):
|
|
563
|
+
def decorator(func: Callable[[Any, Message], None]):
|
|
564
|
+
async def wrapper(bot, message: Message):
|
|
565
|
+
if filters and not filters(message):
|
|
566
|
+
return
|
|
567
|
+
if commands:
|
|
568
|
+
if not message.is_command:
|
|
569
|
+
return
|
|
570
|
+
cmd = message.text.split()[0].lstrip("/")
|
|
571
|
+
if cmd not in commands:
|
|
572
|
+
return
|
|
573
|
+
|
|
574
|
+
return await func(bot, message)
|
|
575
|
+
self._message_handlers.append({
|
|
576
|
+
"func": wrapper,
|
|
577
|
+
"filters": filters,
|
|
578
|
+
"commands": commands
|
|
579
|
+
})
|
|
580
|
+
self._edited_message_handlers.append({
|
|
581
|
+
"func": wrapper,
|
|
582
|
+
"filters": filters,
|
|
583
|
+
"commands": commands
|
|
584
|
+
})
|
|
585
|
+
|
|
586
|
+
return wrapper
|
|
587
|
+
return decorator
|
|
526
588
|
|
|
527
589
|
|
|
528
590
|
def on_message_file(self, filters: Optional[Callable[[Message], bool]] = None, commands: Optional[List[str]] = None):
|
|
@@ -837,14 +899,17 @@ class Robot:
|
|
|
837
899
|
response.raise_for_status()
|
|
838
900
|
return await response.json()
|
|
839
901
|
|
|
840
|
-
def _is_duplicate(self,
|
|
902
|
+
def _is_duplicate(self, key: str, max_age_sec: int = 300) -> bool:
|
|
841
903
|
now = time.time()
|
|
842
904
|
expired = [mid for mid, ts in self._processed_message_ids.items() if now - ts > max_age_sec]
|
|
843
|
-
for mid in expired:
|
|
844
|
-
|
|
845
|
-
self._processed_message_ids
|
|
905
|
+
for mid in expired:
|
|
906
|
+
del self._processed_message_ids[mid]
|
|
907
|
+
if key in self._processed_message_ids:
|
|
908
|
+
return True
|
|
909
|
+
self._processed_message_ids[key] = now
|
|
910
|
+
if len(self._processed_message_ids) > self._max_cache_size:
|
|
911
|
+
self._processed_message_ids.popitem(last=False)
|
|
846
912
|
return False
|
|
847
|
-
|
|
848
913
|
|
|
849
914
|
async def run(
|
|
850
915
|
self,
|
|
@@ -1282,24 +1347,36 @@ class Robot:
|
|
|
1282
1347
|
for update in updates:
|
|
1283
1348
|
message_id = None
|
|
1284
1349
|
if update.get("type") == "NewMessage":
|
|
1285
|
-
|
|
1350
|
+
msg_data = update.get("new_message", {})
|
|
1351
|
+
message_id = msg_data.get("message_id")
|
|
1352
|
+
text_content = msg_data.get("text", "")
|
|
1353
|
+
msg_time = int(msg_data.get("time", 0))
|
|
1286
1354
|
elif update.get("type") == "ReceiveQuery":
|
|
1287
|
-
|
|
1355
|
+
msg_data = update.get("inline_message", {})
|
|
1356
|
+
message_id = msg_data.get("message_id")
|
|
1357
|
+
text_content = msg_data.get("text", "")
|
|
1358
|
+
msg_time = int(msg_data.get("time", 0))
|
|
1288
1359
|
elif update.get("type") == "UpdatedMessage":
|
|
1289
|
-
|
|
1360
|
+
msg_data = update.get("updated_message", {})
|
|
1361
|
+
message_id = msg_data.get("message_id")
|
|
1362
|
+
text_content = msg_data.get("text", "")
|
|
1363
|
+
msg_time = int(msg_data.get("time", 0))
|
|
1290
1364
|
elif "message_id" in update:
|
|
1291
1365
|
message_id = update.get("message_id")
|
|
1292
|
-
|
|
1366
|
+
now = int(time.time())
|
|
1367
|
+
if msg_time and (now - msg_time > self.max_msg_age):
|
|
1368
|
+
continue
|
|
1293
1369
|
dup_ok = True
|
|
1294
|
-
if ignore_duplicate_messages:
|
|
1295
|
-
|
|
1370
|
+
if ignore_duplicate_messages and message_id:
|
|
1371
|
+
dup_key = self._make_dup_key(message_id, update.get("type", ""), msg_data)
|
|
1372
|
+
dup_ok = not self._is_duplicate(dup_key)
|
|
1296
1373
|
if message_id and dup_ok:
|
|
1297
1374
|
received_updates.append(update)
|
|
1298
1375
|
|
|
1299
1376
|
|
|
1300
1377
|
if not received_updates:
|
|
1301
1378
|
if pause_on_idle and sleep_time == 0:
|
|
1302
|
-
await asyncio.sleep(0.
|
|
1379
|
+
await asyncio.sleep(0.005)
|
|
1303
1380
|
else:
|
|
1304
1381
|
await asyncio.sleep(sleep_time)
|
|
1305
1382
|
if not loop_forever and max_runtime is None:
|
|
@@ -1430,7 +1507,7 @@ class Robot:
|
|
|
1430
1507
|
disable_notification: bool = False,
|
|
1431
1508
|
reply_to_message_id: Optional[str] = None,
|
|
1432
1509
|
chat_keypad_type: Optional[Literal["New", "Removed"]] = None
|
|
1433
|
-
|
|
1510
|
+
) -> Dict[str, Any]:
|
|
1434
1511
|
payload = {
|
|
1435
1512
|
"chat_id": chat_id,
|
|
1436
1513
|
"text": text,
|
|
@@ -1443,9 +1520,15 @@ class Robot:
|
|
|
1443
1520
|
payload["inline_keypad"] = inline_keypad
|
|
1444
1521
|
if reply_to_message_id:
|
|
1445
1522
|
payload["reply_to_message_id"] = reply_to_message_id
|
|
1446
|
-
|
|
1523
|
+
if self.safeSendMode and reply_to_message_id:
|
|
1524
|
+
try:
|
|
1525
|
+
return await self._post("sendMessage", payload)
|
|
1526
|
+
except Exception:
|
|
1527
|
+
payload.pop("reply_to_message_id", None)
|
|
1528
|
+
return await self._post("sendMessage", payload)
|
|
1529
|
+
else:
|
|
1530
|
+
return await self._post("sendMessage", payload)
|
|
1447
1531
|
|
|
1448
|
-
from typing import Optional, Dict, Any, Literal
|
|
1449
1532
|
|
|
1450
1533
|
async def send_sticker(
|
|
1451
1534
|
self,
|
|
@@ -1494,22 +1577,6 @@ class Robot:
|
|
|
1494
1577
|
return Client_get(self.session_name, self.auth, self.Key, self.platform)
|
|
1495
1578
|
else:
|
|
1496
1579
|
return Client_get(show_last_six_words(self.token), self.auth, self.Key, self.platform)
|
|
1497
|
-
|
|
1498
|
-
async def check_join(self, channel_guid: str, chat_id: str = None) -> Union[bool, list[str]]:
|
|
1499
|
-
client = self._get_client()
|
|
1500
|
-
if chat_id:
|
|
1501
|
-
chat_info_data = await self.get_chat(chat_id)
|
|
1502
|
-
chat_info = chat_info_data.get('data', {}).get('chat', {})
|
|
1503
|
-
username = chat_info.get('username')
|
|
1504
|
-
user_id = chat_info.get('user_id')
|
|
1505
|
-
if username:
|
|
1506
|
-
result = await asyncio.to_thread(self.get_all_member, channel_guid, search_text=username)
|
|
1507
|
-
members = result.get('in_chat_members', [])
|
|
1508
|
-
return any(m.get('username') == username for m in members)
|
|
1509
|
-
elif user_id:
|
|
1510
|
-
member_guids = await asyncio.to_thread(client.get_all_members, channel_guid, just_get_guids=True)
|
|
1511
|
-
return user_id in member_guids
|
|
1512
|
-
return False
|
|
1513
1580
|
async def send_button_join(
|
|
1514
1581
|
self,
|
|
1515
1582
|
chat_id,
|
|
@@ -1595,21 +1662,15 @@ class Robot:
|
|
|
1595
1662
|
inline_keypad=builder.build(),
|
|
1596
1663
|
reply_to_message_id=reply_to_message_id
|
|
1597
1664
|
)
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
return
|
|
1601
|
-
async def send_poll(self, chat_id: str, question: str, options: List[str]) -> Dict[str, Any]:
|
|
1602
|
-
return await self._post("sendPoll", {"chat_id": chat_id, "question": question, "options": options})
|
|
1665
|
+
|
|
1666
|
+
async def close_poll(self, chat_id: str, message_id: str) -> Dict[str, Any]:
|
|
1667
|
+
return await self._post("closePoll", {"chat_id": chat_id, "message_id": message_id})
|
|
1603
1668
|
async def send_location(self, chat_id: str, latitude: str, longitude: str, disable_notification: bool = False, inline_keypad: Optional[Dict[str, Any]] = None, reply_to_message_id: Optional[str] = None, chat_keypad_type: Optional[Literal["New", "Removed"]] = None) -> Dict[str, Any]:
|
|
1604
1669
|
payload = {"chat_id": chat_id, "latitude": latitude, "longitude": longitude, "disable_notification": disable_notification}
|
|
1605
1670
|
if inline_keypad: payload["inline_keypad"] = inline_keypad
|
|
1606
1671
|
if reply_to_message_id: payload["reply_to_message_id"] = reply_to_message_id
|
|
1607
1672
|
if chat_keypad_type: payload["chat_keypad_type"] = chat_keypad_type
|
|
1608
1673
|
return await self._post("sendLocation", {k: v for k, v in payload.items() if v is not None})
|
|
1609
|
-
async def send_contact(self, chat_id: str, first_name: str, last_name: str, phone_number: str) -> Dict[str, Any]:
|
|
1610
|
-
return await self._post("sendContact", {"chat_id": chat_id, "first_name": first_name, "last_name": last_name, "phone_number": phone_number})
|
|
1611
|
-
async def get_chat(self, chat_id: str) -> Dict[str, Any]:
|
|
1612
|
-
return await self._post("getChat", {"chat_id": chat_id})
|
|
1613
1674
|
async def upload_media_file(self, upload_url: str, name: str, path: Union[str, Path]) -> str:
|
|
1614
1675
|
is_temp_file = False
|
|
1615
1676
|
session = await self._get_session()
|
|
@@ -1725,14 +1786,12 @@ class Robot:
|
|
|
1725
1786
|
raise asyncio.TimeoutError("The download operation timed out.")
|
|
1726
1787
|
except Exception as e:
|
|
1727
1788
|
raise Exception(f"An error occurred while downloading the file: {e}")
|
|
1728
|
-
|
|
1729
1789
|
async def get_upload_url(self, media_type: Literal['File', 'Image', 'voice', 'Music', 'Gif', 'Video']) -> str:
|
|
1730
1790
|
allowed = ['File', 'Image', 'voice', 'Music', 'Gif', 'Video']
|
|
1731
1791
|
if media_type not in allowed:
|
|
1732
1792
|
raise ValueError(f"Invalid media type. Must be one of {allowed}")
|
|
1733
1793
|
result = await self._post("requestSendFile", {"type": media_type})
|
|
1734
1794
|
return result.get("data", {}).get("upload_url")
|
|
1735
|
-
|
|
1736
1795
|
async def _send_uploaded_file(self, chat_id: str, file_id: str,type_file : str = "file",text: Optional[str] = None, chat_keypad: Optional[Dict[str, Any]] = None, inline_keypad: Optional[Dict[str, Any]] = None, disable_notification: bool = False, reply_to_message_id: Optional[str] = None, chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None") -> Dict[str, Any]:
|
|
1737
1796
|
payload = {"chat_id": chat_id, "file_id": file_id, "text": text, "disable_notification": disable_notification, "chat_keypad_type": chat_keypad_type}
|
|
1738
1797
|
if chat_keypad: payload["chat_keypad"] = chat_keypad
|
|
@@ -1757,7 +1816,6 @@ class Robot:
|
|
|
1757
1816
|
"chat_keypad_type":chat_keypad_type
|
|
1758
1817
|
}
|
|
1759
1818
|
return AttrDict(result)
|
|
1760
|
-
|
|
1761
1819
|
async def _send_file_generic(self, media_type, chat_id, path, file_id, text, file_name, inline_keypad, chat_keypad, reply_to_message_id, disable_notification, chat_keypad_type):
|
|
1762
1820
|
if path:
|
|
1763
1821
|
file_name = file_name or Path(path).name
|
|
@@ -1766,14 +1824,12 @@ class Robot:
|
|
|
1766
1824
|
if not file_id:
|
|
1767
1825
|
raise ValueError("Either path or file_id must be provided.")
|
|
1768
1826
|
return await self._send_uploaded_file(chat_id=chat_id, file_id=file_id, text=text, inline_keypad=inline_keypad, chat_keypad=chat_keypad, reply_to_message_id=reply_to_message_id, disable_notification=disable_notification, chat_keypad_type=chat_keypad_type,type_file=media_type)
|
|
1769
|
-
|
|
1770
1827
|
async def send_document(self, chat_id: str, path: Optional[Union[str, Path]] = None, file_id: Optional[str] = None, text: Optional[str] = None, file_name: Optional[str] = None, inline_keypad: Optional[Dict[str, Any]] = None, chat_keypad: Optional[Dict[str, Any]] = None, reply_to_message_id: Optional[str] = None, disable_notification: bool = False, chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None") -> Dict[str, Any]:
|
|
1771
1828
|
return await self._send_file_generic("File", chat_id, path, file_id, text, file_name, inline_keypad, chat_keypad, reply_to_message_id, disable_notification, chat_keypad_type)
|
|
1772
1829
|
async def send_file(self, chat_id: str, path: Optional[Union[str, Path]] = None, file_id: Optional[str] = None, caption: Optional[str] = None, file_name: Optional[str] = None, inline_keypad: Optional[Dict[str, Any]] = None, chat_keypad: Optional[Dict[str, Any]] = None, reply_to_message_id: Optional[str] = None, disable_notification: bool = False, chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None") -> Dict[str, Any]:
|
|
1773
1830
|
return await self._send_file_generic("File", chat_id, path, file_id, caption, file_name, inline_keypad, chat_keypad, reply_to_message_id, disable_notification, chat_keypad_type)
|
|
1774
1831
|
async def re_send(self, chat_id: str, path: Optional[Union[str, Path]] = None, file_id: Optional[str] = None, caption: Optional[str] = None, file_name: Optional[str] = None, inline_keypad: Optional[Dict[str, Any]] = None, chat_keypad: Optional[Dict[str, Any]] = None, reply_to_message_id: Optional[str] = None, disable_notification: bool = False, chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None") -> Dict[str, Any]:
|
|
1775
1832
|
return await self._send_file_generic("File", chat_id, path, file_id, caption, file_name, inline_keypad, chat_keypad, reply_to_message_id, disable_notification, chat_keypad_type)
|
|
1776
|
-
|
|
1777
1833
|
async def send_music(
|
|
1778
1834
|
self,
|
|
1779
1835
|
chat_id: str,
|
|
@@ -1819,12 +1875,6 @@ class Robot:
|
|
|
1819
1875
|
disable_notification,
|
|
1820
1876
|
chat_keypad_type
|
|
1821
1877
|
)
|
|
1822
|
-
async def send_video(self, chat_id: str, path: Optional[Union[str, Path]] = None, file_id: Optional[str] = None, text: Optional[str] = None, file_name: Optional[str] = None, inline_keypad: Optional[Dict[str, Any]] = None, chat_keypad: Optional[Dict[str, Any]] = None, reply_to_message_id: Optional[str] = None, disable_notification: bool = False, chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None") -> Dict[str, Any]:
|
|
1823
|
-
return await self._send_file_generic("Video", chat_id, path, file_id, text, file_name, inline_keypad, chat_keypad, reply_to_message_id, disable_notification, chat_keypad_type)
|
|
1824
|
-
async def send_voice(self, chat_id: str, path: Optional[Union[str, Path]] = None, file_id: Optional[str] = None, text: Optional[str] = None, file_name: Optional[str] = None, inline_keypad: Optional[Dict[str, Any]] = None, chat_keypad: Optional[Dict[str, Any]] = None, reply_to_message_id: Optional[str] = None, disable_notification: bool = False, chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None") -> Dict[str, Any]:
|
|
1825
|
-
return await self._send_file_generic("voice", chat_id, path, file_id, text, file_name, inline_keypad, chat_keypad, reply_to_message_id, disable_notification, chat_keypad_type)
|
|
1826
|
-
async def send_image(self, chat_id: str, path: Optional[Union[str, Path]] = None, file_id: Optional[str] = None, text: Optional[str] = None, file_name: Optional[str] = None, inline_keypad: Optional[Dict[str, Any]] = None, chat_keypad: Optional[Dict[str, Any]] = None, reply_to_message_id: Optional[str] = None, disable_notification: bool = False, chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None") -> Dict[str, Any]:
|
|
1827
|
-
return await self._send_file_generic("Image", chat_id, path, file_id, text, file_name, inline_keypad, chat_keypad, reply_to_message_id, disable_notification, chat_keypad_type)
|
|
1828
1878
|
async def send_gif(
|
|
1829
1879
|
self,
|
|
1830
1880
|
chat_id: str,
|
|
@@ -1870,23 +1920,33 @@ class Robot:
|
|
|
1870
1920
|
disable_notification,
|
|
1871
1921
|
chat_keypad_type
|
|
1872
1922
|
)
|
|
1873
|
-
async def
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1923
|
+
async def get_avatar_me(
|
|
1924
|
+
self,
|
|
1925
|
+
save_as: str = None) -> str:
|
|
1926
|
+
"""
|
|
1927
|
+
Get the bot's profile photo URL and optionally save it locally.
|
|
1928
|
+
Args:
|
|
1929
|
+
save_as (str, optional): File name to save the avatar locally.
|
|
1930
|
+
Returns:
|
|
1931
|
+
str: Download URL of the bot's avatar, or "null" if not available.
|
|
1932
|
+
"""
|
|
1933
|
+
try:
|
|
1934
|
+
me_info = await self.get_me()
|
|
1935
|
+
avatar = me_info.get('data', {}).get('bot', {}).get('avatar', {})
|
|
1936
|
+
file_id = avatar.get('file_id')
|
|
1937
|
+
if not file_id:
|
|
1938
|
+
return None
|
|
1939
|
+
url = await self.get_url_file(file_id)
|
|
1940
|
+
if save_as:
|
|
1941
|
+
async with aiohttp.ClientSession() as session:
|
|
1942
|
+
async with session.get(url) as resp:
|
|
1943
|
+
if resp.status == 200:
|
|
1944
|
+
content = await resp.read()
|
|
1945
|
+
with open(save_as, "wb") as f:
|
|
1946
|
+
f.write(content)
|
|
1947
|
+
return url
|
|
1948
|
+
except Exception:
|
|
1949
|
+
return None
|
|
1890
1950
|
async def get_name(self, chat_id: str) -> str:
|
|
1891
1951
|
try:
|
|
1892
1952
|
chat = await self.get_chat(chat_id)
|
|
@@ -1904,4 +1964,99 @@ class Robot:
|
|
|
1904
1964
|
except Exception:return "null"
|
|
1905
1965
|
async def get_username(self, chat_id: str) -> str:
|
|
1906
1966
|
chat_info = await self.get_chat(chat_id)
|
|
1907
|
-
return chat_info.get("data", {}).get("chat", {}).get("username", "None")
|
|
1967
|
+
return chat_info.get("data", {}).get("chat", {}).get("username", "None")
|
|
1968
|
+
async def get_chat_admins(self, chat_id: str) -> Dict[str, Any]:
|
|
1969
|
+
return await self._post("getChatAdmins", {"chat_id": chat_id})
|
|
1970
|
+
async def get_chat_members(self, chat_id: str, start_id: str = "") -> Dict[str, Any]:
|
|
1971
|
+
return await self._post("getChatMembers", {"chat_id": chat_id, "start_id": start_id})
|
|
1972
|
+
async def get_chat_info(self, chat_id: str) -> Dict[str, Any]:
|
|
1973
|
+
return await self._post("getChatInfo", {"chat_id": chat_id})
|
|
1974
|
+
async def set_chat_title(self, chat_id: str, title: str) -> Dict[str, Any]:
|
|
1975
|
+
return await self._post("editChatTitle", {"chat_id": chat_id, "title": title})
|
|
1976
|
+
async def set_chat_description(self, chat_id: str, description: str) -> Dict[str, Any]:
|
|
1977
|
+
return await self._post("editChatDescription", {"chat_id": chat_id, "description": description})
|
|
1978
|
+
async def set_chat_photo(self, chat_id: str, file_id: str) -> Dict[str, Any]:
|
|
1979
|
+
return await self._post("editChatPhoto", {"chat_id": chat_id, "file_id": file_id})
|
|
1980
|
+
async def remove_chat_photo(self, chat_id: str) -> Dict[str, Any]:
|
|
1981
|
+
return await self._post("editChatPhoto", {"chat_id": chat_id, "file_id": "Removed"})
|
|
1982
|
+
async def add_member_chat(self, chat_id: str, user_ids: list[str]) -> Dict[str, Any]:
|
|
1983
|
+
return await self._post("addChatMembers", {"chat_id": chat_id, "member_ids": user_ids})
|
|
1984
|
+
async def ban_member_chat(self, chat_id: str, user_id: str) -> Dict[str, Any]:
|
|
1985
|
+
return await self._post("banChatMember", {"chat_id": chat_id, "member_id": user_id})
|
|
1986
|
+
async def unban_chat_member(self, chat_id: str, user_id: str) -> Dict[str, Any]:
|
|
1987
|
+
return await self._post("unbanChatMember", {"chat_id": chat_id, "member_id": user_id})
|
|
1988
|
+
async def restrict_chat_member(self, chat_id: str, user_id: str, until: int = 0) -> Dict[str, Any]:
|
|
1989
|
+
return await self._post("restrictChatMember", {"chat_id": chat_id, "member_id": user_id, "until_date": until})
|
|
1990
|
+
async def get_chat_member(self, chat_id: str, user_id: str):
|
|
1991
|
+
return await self._post("getChatMember", {"chat_id": chat_id, "user_id": user_id})
|
|
1992
|
+
async def get_admin_chat(self, chat_id: str):
|
|
1993
|
+
return await self._post("getChatAdministrators", {"chat_id": chat_id})
|
|
1994
|
+
async def get_chat_member_count(self, chat_id: str):
|
|
1995
|
+
return await self._post("getChatMemberCount", {"chat_id": chat_id})
|
|
1996
|
+
async def ban_chat_member(self, chat_id: str, user_id: str):
|
|
1997
|
+
return await self._post("banChatMember", {"chat_id": chat_id, "user_id": user_id})
|
|
1998
|
+
async def promote_chat_member(self, chat_id: str, user_id: str, rights: dict) -> Dict[str, Any]:
|
|
1999
|
+
return await self._post("promoteChatMember", {"chat_id": chat_id, "member_id": user_id, "rights": rights})
|
|
2000
|
+
async def demote_chat_member(self, chat_id: str, user_id: str) -> Dict[str, Any]:
|
|
2001
|
+
return await self._post("promoteChatMember", {"chat_id": chat_id, "member_id": user_id, "rights": {}})
|
|
2002
|
+
async def pin_chat_message(self, chat_id: str, message_id: str) -> Dict[str, Any]:
|
|
2003
|
+
return await self._post("pinChatMessage", {"chat_id": chat_id, "message_id": message_id})
|
|
2004
|
+
async def unpin_chat_message(self, chat_id: str, message_id: str = "") -> Dict[str, Any]:
|
|
2005
|
+
return await self._post("unpinChatMessage", {"chat_id": chat_id, "message_id": message_id})
|
|
2006
|
+
async def export_chat_invite_link(self, chat_id: str) -> Dict[str, Any]:
|
|
2007
|
+
return await self._post("exportChatInviteLink", {"chat_id": chat_id})
|
|
2008
|
+
async def revoke_chat_invite_link(self, chat_id: str, link: str) -> Dict[str, Any]:
|
|
2009
|
+
return await self._post("revokeChatInviteLink", {"chat_id": chat_id, "invite_link": link})
|
|
2010
|
+
async def create_group(self, title: str, user_ids: list[str]) -> Dict[str, Any]:
|
|
2011
|
+
return await self._post("createGroup", {"title": title, "user_ids": user_ids})
|
|
2012
|
+
async def create_channel(self, title: str, description: str = "") -> Dict[str, Any]:
|
|
2013
|
+
return await self._post("createChannel", {"title": title, "description": description})
|
|
2014
|
+
async def leave_chat(self, chat_id: str) -> Dict[str, Any]:
|
|
2015
|
+
return await self._post("leaveChat", {"chat_id": chat_id})
|
|
2016
|
+
async def forward_message(self, from_chat_id: str, message_id: str, to_chat_id: str, disable_notification: bool = False) -> Dict[str, Any]:
|
|
2017
|
+
return await self._post("forwardMessage", {"from_chat_id": from_chat_id, "message_id": message_id, "to_chat_id": to_chat_id, "disable_notification": disable_notification})
|
|
2018
|
+
async def edit_message_text(self, chat_id: str, message_id: str, text: str) -> Dict[str, Any]:
|
|
2019
|
+
return await self._post("editMessageText", {"chat_id": chat_id, "message_id": message_id, "text": text})
|
|
2020
|
+
async def edit_inline_keypad(self,chat_id: str,message_id: str,inline_keypad: Dict[str, Any],text: str = None) -> Dict[str, Any]:
|
|
2021
|
+
if text is not None:await self._post("editMessageText", {"chat_id": chat_id,"message_id": message_id,"text": text})
|
|
2022
|
+
return await self._post("editMessageKeypad", {"chat_id": chat_id,"message_id": message_id,"inline_keypad": inline_keypad})
|
|
2023
|
+
async def delete_message(self, chat_id: str, message_id: str) -> Dict[str, Any]:
|
|
2024
|
+
return await self._post("deleteMessage", {"chat_id": chat_id, "message_id": message_id})
|
|
2025
|
+
async def set_commands(self, bot_commands: List[Dict[str, str]]) -> Dict[str, Any]:
|
|
2026
|
+
return await self._post("setCommands", {"bot_commands": bot_commands})
|
|
2027
|
+
async def update_bot_endpoint(self, url: str, type: str) -> Dict[str, Any]:
|
|
2028
|
+
return await self._post("updateBotEndpoints", {"url": url, "type": type})
|
|
2029
|
+
async def remove_keypad(self, chat_id: str) -> Dict[str, Any]:
|
|
2030
|
+
return await self._post("editChatKeypad", {"chat_id": chat_id, "chat_keypad_type": "Removed"})
|
|
2031
|
+
async def edit_chat_keypad(self, chat_id: str, chat_keypad: Dict[str, Any]) -> Dict[str, Any]:
|
|
2032
|
+
return await self._post("editChatKeypad", {"chat_id": chat_id, "chat_keypad_type": "New", "chat_keypad": chat_keypad})
|
|
2033
|
+
async def send_contact(self, chat_id: str, first_name: str, last_name: str, phone_number: str) -> Dict[str, Any]:
|
|
2034
|
+
return await self._post("sendContact", {"chat_id": chat_id, "first_name": first_name, "last_name": last_name, "phone_number": phone_number})
|
|
2035
|
+
async def get_chat(self, chat_id: str) -> Dict[str, Any]:
|
|
2036
|
+
return await self._post("getChat", {"chat_id": chat_id})
|
|
2037
|
+
async def send_video(self, chat_id: str, path: Optional[Union[str, Path]] = None, file_id: Optional[str] = None, text: Optional[str] = None, file_name: Optional[str] = None, inline_keypad: Optional[Dict[str, Any]] = None, chat_keypad: Optional[Dict[str, Any]] = None, reply_to_message_id: Optional[str] = None, disable_notification: bool = False, chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None") -> Dict[str, Any]:
|
|
2038
|
+
return await self._send_file_generic("Video", chat_id, path, file_id, text, file_name, inline_keypad, chat_keypad, reply_to_message_id, disable_notification, chat_keypad_type)
|
|
2039
|
+
async def send_voice(self, chat_id: str, path: Optional[Union[str, Path]] = None, file_id: Optional[str] = None, text: Optional[str] = None, file_name: Optional[str] = None, inline_keypad: Optional[Dict[str, Any]] = None, chat_keypad: Optional[Dict[str, Any]] = None, reply_to_message_id: Optional[str] = None, disable_notification: bool = False, chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None") -> Dict[str, Any]:
|
|
2040
|
+
return await self._send_file_generic("voice", chat_id, path, file_id, text, file_name, inline_keypad, chat_keypad, reply_to_message_id, disable_notification, chat_keypad_type)
|
|
2041
|
+
async def send_image(self, chat_id: str, path: Optional[Union[str, Path]] = None, file_id: Optional[str] = None, text: Optional[str] = None, file_name: Optional[str] = None, inline_keypad: Optional[Dict[str, Any]] = None, chat_keypad: Optional[Dict[str, Any]] = None, reply_to_message_id: Optional[str] = None, disable_notification: bool = False, chat_keypad_type: Optional[Literal["New", "Removed", "None"]] = "None") -> Dict[str, Any]:
|
|
2042
|
+
return await self._send_file_generic("Image", chat_id, path, file_id, text, file_name, inline_keypad, chat_keypad, reply_to_message_id, disable_notification, chat_keypad_type)
|
|
2043
|
+
def get_all_member(self, channel_guid: str, search_text: str = None, start_id: str = None, just_get_guids: bool = False):
|
|
2044
|
+
client = self._get_client()
|
|
2045
|
+
return client.get_all_members(channel_guid, search_text, start_id, just_get_guids)
|
|
2046
|
+
async def send_poll(self, chat_id: str, question: str, options: List[str]) -> Dict[str, Any]:
|
|
2047
|
+
return await self._post("sendPoll", {"chat_id": chat_id, "question": question, "options": options})
|
|
2048
|
+
async def check_join(self, channel_guid: str, chat_id: str = None) -> Union[bool, list[str]]:
|
|
2049
|
+
client = self._get_client()
|
|
2050
|
+
if chat_id:
|
|
2051
|
+
chat_info_data = await self.get_chat(chat_id)
|
|
2052
|
+
chat_info = chat_info_data.get('data', {}).get('chat', {})
|
|
2053
|
+
username = chat_info.get('username')
|
|
2054
|
+
user_id = chat_info.get('user_id')
|
|
2055
|
+
if username:
|
|
2056
|
+
result = await asyncio.to_thread(self.get_all_member, channel_guid, search_text=username)
|
|
2057
|
+
members = result.get('in_chat_members', [])
|
|
2058
|
+
return any(m.get('username') == username for m in members)
|
|
2059
|
+
elif user_id:
|
|
2060
|
+
member_guids = await asyncio.to_thread(client.get_all_members, channel_guid, just_get_guids=True)
|
|
2061
|
+
return user_id in member_guids
|
|
2062
|
+
return False
|
rubka/context.py
CHANGED
|
@@ -508,20 +508,14 @@ class InlineMessage:
|
|
|
508
508
|
self.file = File(self.raw_data["file"]) if "file" in self.raw_data else None
|
|
509
509
|
self.sticker = Sticker(self.raw_data["sticker"]) if "sticker" in self.raw_data else None
|
|
510
510
|
self.contact_message = ContactMessage(self.raw_data["contact_message"]) if "contact_message" in self.raw_data else None
|
|
511
|
-
self.poll = Poll(self.raw_data["poll"]) if "poll" in self.raw_data else None
|
|
512
|
-
self.location = Location(self.raw_data["location"]) if "location" in self.raw_data else None
|
|
513
|
-
self.live_location = LiveLocation(self.raw_data["live_location"]) if "live_location" in self.raw_data else None
|
|
514
511
|
self.aux_data = AuxData(self.raw_data["aux_data"]) if "aux_data" in self.raw_data else None
|
|
515
512
|
self.is_reply = self.reply_to_message_id is not None
|
|
516
|
-
self.has_media = any([self.file, self.sticker
|
|
513
|
+
self.has_media = any([self.file, self.sticker])
|
|
517
514
|
self.is_forwarded = self.forwarded_from is not None
|
|
518
515
|
self.is_text = bool(self.text and not self.has_media)
|
|
519
516
|
self.is_media = self.has_media
|
|
520
|
-
self.is_poll = self.poll is not None
|
|
521
|
-
self.is_location = self.location is not None
|
|
522
|
-
self.is_live_location = self.live_location is not None
|
|
523
517
|
self.is_contact = self.contact_message is not None
|
|
524
|
-
self.has_any_media = any([self.file, self.sticker,
|
|
518
|
+
self.has_any_media = any([self.file, self.sticker,])
|
|
525
519
|
self.edited_text = self.raw_data.get("edited_text") if self.is_edited else None
|
|
526
520
|
if self.file and self.file.file_name:
|
|
527
521
|
name = self.file.file_name.lower()
|
|
@@ -535,10 +529,15 @@ class InlineMessage:
|
|
|
535
529
|
self.is_font = name.endswith((".ttf", ".otf", ".woff", ".woff2"))
|
|
536
530
|
|
|
537
531
|
|
|
532
|
+
@property
|
|
533
|
+
def session(self):
|
|
534
|
+
if self.chat_id not in self.bot.sessions:
|
|
535
|
+
self.bot.sessions[self.chat_id] = {}
|
|
536
|
+
return self.bot.sessions[self.chat_id]
|
|
538
537
|
def reply(self, text: str, **kwargs):
|
|
539
538
|
return self.bot.send_message(
|
|
540
|
-
|
|
541
|
-
text
|
|
539
|
+
self.chat_id,
|
|
540
|
+
text,
|
|
542
541
|
reply_to_message_id=self.message_id,
|
|
543
542
|
**kwargs
|
|
544
543
|
)
|
|
@@ -550,14 +549,212 @@ class InlineMessage:
|
|
|
550
549
|
**kwargs
|
|
551
550
|
)
|
|
552
551
|
|
|
553
|
-
def
|
|
552
|
+
def reply_poll(self, question: str, options: List[str], **kwargs) -> Dict[str, Any]:
|
|
553
|
+
return self.bot._post("sendPoll", {
|
|
554
|
+
"chat_id": self.chat_id,
|
|
555
|
+
"question": question,
|
|
556
|
+
"options": options,
|
|
557
|
+
"reply_to_message_id": self.message_id,
|
|
558
|
+
**kwargs
|
|
559
|
+
})
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
def reply_document(
|
|
563
|
+
self,
|
|
564
|
+
path: Optional[Union[str, Path]] = None,
|
|
565
|
+
file_id: Optional[str] = None,
|
|
566
|
+
text: Optional[str] = None,
|
|
567
|
+
chat_keypad: Optional[Dict[str, Any]] = None,
|
|
568
|
+
inline_keypad: Optional[Dict[str, Any]] = None,
|
|
569
|
+
chat_keypad_type: Optional[str] = "None",
|
|
570
|
+
disable_notification: bool = False
|
|
571
|
+
):
|
|
572
|
+
if chat_keypad and chat_keypad_type == "none":chat_keypad_type == "New"
|
|
573
|
+
return self.bot.send_document(
|
|
574
|
+
chat_id=self.chat_id,
|
|
575
|
+
path=path,
|
|
576
|
+
file_id=file_id,
|
|
577
|
+
text=text,
|
|
578
|
+
chat_keypad=chat_keypad,
|
|
579
|
+
inline_keypad=inline_keypad,
|
|
580
|
+
chat_keypad_type=chat_keypad_type,
|
|
581
|
+
disable_notification=disable_notification,
|
|
582
|
+
reply_to_message_id=self.message_id
|
|
583
|
+
)
|
|
584
|
+
def reply_file(
|
|
585
|
+
self,
|
|
586
|
+
path: Optional[Union[str, Path]] = None,
|
|
587
|
+
file_id: Optional[str] = None,
|
|
588
|
+
text: Optional[str] = None,
|
|
589
|
+
chat_keypad: Optional[Dict[str, Any]] = None,
|
|
590
|
+
inline_keypad: Optional[Dict[str, Any]] = None,
|
|
591
|
+
chat_keypad_type: Optional[str] = "None",
|
|
592
|
+
disable_notification: bool = False
|
|
593
|
+
):
|
|
594
|
+
if chat_keypad and chat_keypad_type == "none":
|
|
595
|
+
chat_keypad_type == "New"
|
|
596
|
+
|
|
597
|
+
return self.bot.send_document(
|
|
598
|
+
chat_id=self.chat_id,
|
|
599
|
+
path=path,
|
|
600
|
+
file_id=file_id,
|
|
601
|
+
text=text,
|
|
602
|
+
chat_keypad=chat_keypad,
|
|
603
|
+
inline_keypad=inline_keypad,
|
|
604
|
+
chat_keypad_type=chat_keypad_type,
|
|
605
|
+
disable_notification=disable_notification,
|
|
606
|
+
reply_to_message_id=self.message_id
|
|
607
|
+
)
|
|
608
|
+
|
|
609
|
+
def reply_image(
|
|
610
|
+
self,
|
|
611
|
+
path: Optional[Union[str, Path]] = None,
|
|
612
|
+
file_id: Optional[str] = None,
|
|
613
|
+
text: Optional[str] = None,
|
|
614
|
+
chat_keypad: Optional[Dict[str, Any]] = None,
|
|
615
|
+
inline_keypad: Optional[Dict[str, Any]] = None,
|
|
616
|
+
chat_keypad_type: Optional[str] = "None",
|
|
617
|
+
disable_notification: bool = False
|
|
618
|
+
):
|
|
619
|
+
if chat_keypad and chat_keypad_type == "none":
|
|
620
|
+
chat_keypad_type == "New"
|
|
621
|
+
return self.bot.send_image(
|
|
622
|
+
chat_id=self.chat_id,
|
|
623
|
+
path=path,
|
|
624
|
+
file_id=file_id,
|
|
625
|
+
text=text,
|
|
626
|
+
chat_keypad=chat_keypad,
|
|
627
|
+
inline_keypad=inline_keypad,
|
|
628
|
+
chat_keypad_type=chat_keypad_type,
|
|
629
|
+
disable_notification=disable_notification,
|
|
630
|
+
reply_to_message_id=self.message_id
|
|
631
|
+
)
|
|
632
|
+
|
|
633
|
+
def reply_music(
|
|
634
|
+
self,
|
|
635
|
+
path: Optional[Union[str, Path]] = None,
|
|
636
|
+
file_id: Optional[str] = None,
|
|
637
|
+
text: Optional[str] = None,
|
|
638
|
+
chat_keypad: Optional[Dict[str, Any]] = None,
|
|
639
|
+
inline_keypad: Optional[Dict[str, Any]] = None,
|
|
640
|
+
chat_keypad_type: Optional[str] = "None",
|
|
641
|
+
disable_notification: bool = False
|
|
642
|
+
):
|
|
643
|
+
if chat_keypad and chat_keypad_type == "none":
|
|
644
|
+
chat_keypad_type == "New"
|
|
645
|
+
return self.bot.send_music(
|
|
646
|
+
chat_id=self.chat_id,
|
|
647
|
+
path=path,
|
|
648
|
+
file_id=file_id,
|
|
649
|
+
text=text,
|
|
650
|
+
chat_keypad=chat_keypad,
|
|
651
|
+
inline_keypad=inline_keypad,
|
|
652
|
+
chat_keypad_type=chat_keypad_type,
|
|
653
|
+
disable_notification=disable_notification,
|
|
654
|
+
reply_to_message_id=self.message_id
|
|
655
|
+
)
|
|
656
|
+
|
|
657
|
+
def reply_voice(
|
|
658
|
+
self,
|
|
659
|
+
path: Optional[Union[str, Path]] = None,
|
|
660
|
+
file_id: Optional[str] = None,
|
|
661
|
+
text: Optional[str] = None,
|
|
662
|
+
chat_keypad: Optional[Dict[str, Any]] = None,
|
|
663
|
+
inline_keypad: Optional[Dict[str, Any]] = None,
|
|
664
|
+
chat_keypad_type: Optional[str] = "None",
|
|
665
|
+
disable_notification: bool = False
|
|
666
|
+
):
|
|
667
|
+
if chat_keypad and chat_keypad_type == "none":
|
|
668
|
+
chat_keypad_type == "New"
|
|
669
|
+
return self.bot.send_voice(
|
|
670
|
+
chat_id=self.chat_id,
|
|
671
|
+
path=path,
|
|
672
|
+
file_id=file_id,
|
|
673
|
+
text=text,
|
|
674
|
+
chat_keypad=chat_keypad,
|
|
675
|
+
inline_keypad=inline_keypad,
|
|
676
|
+
chat_keypad_type=chat_keypad_type,
|
|
677
|
+
disable_notification=disable_notification,
|
|
678
|
+
reply_to_message_id=self.message_id
|
|
679
|
+
)
|
|
680
|
+
|
|
681
|
+
def reply_gif(
|
|
682
|
+
self,
|
|
683
|
+
path: Optional[Union[str, Path]] = None,
|
|
684
|
+
file_id: Optional[str] = None,
|
|
685
|
+
text: Optional[str] = None,
|
|
686
|
+
chat_keypad: Optional[Dict[str, Any]] = None,
|
|
687
|
+
inline_keypad: Optional[Dict[str, Any]] = None,
|
|
688
|
+
chat_keypad_type: Optional[str] = "None",
|
|
689
|
+
disable_notification: bool = False
|
|
690
|
+
):
|
|
691
|
+
if chat_keypad and chat_keypad_type == "none":chat_keypad_type == "New"
|
|
692
|
+
return self.bot.send_gif(
|
|
693
|
+
chat_id=self.chat_id,
|
|
694
|
+
path=path,
|
|
695
|
+
file_id=file_id,
|
|
696
|
+
text=text,
|
|
697
|
+
chat_keypad=chat_keypad,
|
|
698
|
+
inline_keypad=inline_keypad,
|
|
699
|
+
chat_keypad_type=chat_keypad_type,
|
|
700
|
+
disable_notification=disable_notification,
|
|
701
|
+
reply_to_message_id=self.message_id
|
|
702
|
+
)
|
|
703
|
+
|
|
704
|
+
def reply_location(self, latitude: str, longitude: str, **kwargs) -> Dict[str, Any]:
|
|
705
|
+
return self.bot.send_location(
|
|
706
|
+
chat_id=self.chat_id,
|
|
707
|
+
latitude=latitude,
|
|
708
|
+
longitude=longitude,
|
|
709
|
+
reply_to_message_id=self.message_id,
|
|
710
|
+
**kwargs
|
|
711
|
+
)
|
|
712
|
+
|
|
713
|
+
def reply_contact(self, first_name: str, last_name: str, phone_number: str, **kwargs) -> Dict[str, Any]:
|
|
714
|
+
return self.bot.send_contact(
|
|
715
|
+
chat_id=self.chat_id,
|
|
716
|
+
first_name=first_name,
|
|
717
|
+
last_name=last_name,
|
|
718
|
+
phone_number=phone_number,
|
|
719
|
+
reply_to_message_id=self.message_id,
|
|
720
|
+
**kwargs
|
|
721
|
+
)
|
|
722
|
+
|
|
723
|
+
def reply_keypad(self, text: str, keypad: Dict[str, Any], **kwargs) -> Dict[str, Any]:
|
|
724
|
+
return self.bot.send_message(
|
|
725
|
+
chat_id=self.chat_id,
|
|
726
|
+
text=text,
|
|
727
|
+
chat_keypad_type="New",
|
|
728
|
+
chat_keypad=keypad,
|
|
729
|
+
reply_to_message_id=self.message_id,
|
|
730
|
+
**kwargs
|
|
731
|
+
)
|
|
732
|
+
|
|
733
|
+
def reply_inline(self, text: str, inline_keypad: Dict[str, Any], **kwargs) -> Dict[str, Any]:
|
|
734
|
+
return self.bot.send_message(
|
|
735
|
+
chat_id=self.chat_id,
|
|
736
|
+
text=text,
|
|
737
|
+
inline_keypad=inline_keypad,
|
|
738
|
+
reply_to_message_id=self.message_id,
|
|
739
|
+
**kwargs
|
|
740
|
+
)
|
|
741
|
+
|
|
742
|
+
def reply_sticker(self, sticker_id: str, **kwargs) -> Dict[str, Any]:
|
|
743
|
+
return self.bot._post("sendSticker", {
|
|
744
|
+
"chat_id": self.chat_id,
|
|
745
|
+
"sticker_id": sticker_id,
|
|
746
|
+
"reply_to_message_id": self.message_id,
|
|
747
|
+
**kwargs
|
|
748
|
+
})
|
|
749
|
+
|
|
750
|
+
def edit(self, new_text: str) -> Dict[str, Any]:
|
|
554
751
|
return self.bot.edit_message_text(
|
|
555
752
|
chat_id=self.chat_id,
|
|
556
753
|
message_id=self.message_id,
|
|
557
754
|
text=new_text
|
|
558
755
|
)
|
|
559
756
|
|
|
560
|
-
def delete(self):
|
|
757
|
+
def delete(self) -> Dict[str, Any]:
|
|
561
758
|
return self.bot.delete_message(
|
|
562
759
|
chat_id=self.chat_id,
|
|
563
760
|
message_id=self.message_id
|
rubka/exceptions.py
CHANGED
|
@@ -1,3 +1,37 @@
|
|
|
1
1
|
class APIRequestError(Exception):
|
|
2
|
-
"""
|
|
2
|
+
"""Base class for all API request errors."""
|
|
3
|
+
def __init__(self, status: str, dev_message: str = None):
|
|
4
|
+
self.status = status
|
|
5
|
+
self.dev_message = dev_message
|
|
6
|
+
msg = f"{self.__class__.__name__}: {status}"
|
|
7
|
+
if dev_message:
|
|
8
|
+
msg += f" | Message : {dev_message}"
|
|
9
|
+
super().__init__(msg)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class InvalidAccessError(APIRequestError):
|
|
13
|
+
"""Raised when access is invalid."""
|
|
14
|
+
|
|
15
|
+
class InvalidTokenError(Exception):
|
|
3
16
|
pass
|
|
17
|
+
|
|
18
|
+
class InvalidInputError(APIRequestError):
|
|
19
|
+
"""Raised when input is invalid."""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class TooRequestError(APIRequestError):
|
|
23
|
+
"""Raised when too many requests are made."""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def raise_for_status(response: dict):
|
|
27
|
+
status = response.get("status")
|
|
28
|
+
dev_message = response.get("dev_message")
|
|
29
|
+
|
|
30
|
+
if status == "INVALID_ACCESS":
|
|
31
|
+
raise InvalidAccessError(status, dev_message)
|
|
32
|
+
elif status == "INVALID_INPUT":
|
|
33
|
+
raise InvalidInputError(status, dev_message)
|
|
34
|
+
elif status == "TOO_REQUEST":
|
|
35
|
+
raise TooRequestError(status, dev_message)
|
|
36
|
+
elif status != "OK":
|
|
37
|
+
raise APIRequestError(status, dev_message)
|
rubka/update.py
CHANGED
|
@@ -508,20 +508,14 @@ class InlineMessage:
|
|
|
508
508
|
self.file = File(self.raw_data["file"]) if "file" in self.raw_data else None
|
|
509
509
|
self.sticker = Sticker(self.raw_data["sticker"]) if "sticker" in self.raw_data else None
|
|
510
510
|
self.contact_message = ContactMessage(self.raw_data["contact_message"]) if "contact_message" in self.raw_data else None
|
|
511
|
-
self.poll = Poll(self.raw_data["poll"]) if "poll" in self.raw_data else None
|
|
512
|
-
self.location = Location(self.raw_data["location"]) if "location" in self.raw_data else None
|
|
513
|
-
self.live_location = LiveLocation(self.raw_data["live_location"]) if "live_location" in self.raw_data else None
|
|
514
511
|
self.aux_data = AuxData(self.raw_data["aux_data"]) if "aux_data" in self.raw_data else None
|
|
515
512
|
self.is_reply = self.reply_to_message_id is not None
|
|
516
|
-
self.has_media = any([self.file, self.sticker
|
|
513
|
+
self.has_media = any([self.file, self.sticker])
|
|
517
514
|
self.is_forwarded = self.forwarded_from is not None
|
|
518
515
|
self.is_text = bool(self.text and not self.has_media)
|
|
519
516
|
self.is_media = self.has_media
|
|
520
|
-
self.is_poll = self.poll is not None
|
|
521
|
-
self.is_location = self.location is not None
|
|
522
|
-
self.is_live_location = self.live_location is not None
|
|
523
517
|
self.is_contact = self.contact_message is not None
|
|
524
|
-
self.has_any_media = any([self.file, self.sticker,
|
|
518
|
+
self.has_any_media = any([self.file, self.sticker,])
|
|
525
519
|
self.edited_text = self.raw_data.get("edited_text") if self.is_edited else None
|
|
526
520
|
if self.file and self.file.file_name:
|
|
527
521
|
name = self.file.file_name.lower()
|
|
@@ -535,10 +529,15 @@ class InlineMessage:
|
|
|
535
529
|
self.is_font = name.endswith((".ttf", ".otf", ".woff", ".woff2"))
|
|
536
530
|
|
|
537
531
|
|
|
532
|
+
@property
|
|
533
|
+
def session(self):
|
|
534
|
+
if self.chat_id not in self.bot.sessions:
|
|
535
|
+
self.bot.sessions[self.chat_id] = {}
|
|
536
|
+
return self.bot.sessions[self.chat_id]
|
|
538
537
|
def reply(self, text: str, **kwargs):
|
|
539
538
|
return self.bot.send_message(
|
|
540
|
-
|
|
541
|
-
text
|
|
539
|
+
self.chat_id,
|
|
540
|
+
text,
|
|
542
541
|
reply_to_message_id=self.message_id,
|
|
543
542
|
**kwargs
|
|
544
543
|
)
|
|
@@ -550,14 +549,212 @@ class InlineMessage:
|
|
|
550
549
|
**kwargs
|
|
551
550
|
)
|
|
552
551
|
|
|
553
|
-
def
|
|
552
|
+
def reply_poll(self, question: str, options: List[str], **kwargs) -> Dict[str, Any]:
|
|
553
|
+
return self.bot._post("sendPoll", {
|
|
554
|
+
"chat_id": self.chat_id,
|
|
555
|
+
"question": question,
|
|
556
|
+
"options": options,
|
|
557
|
+
"reply_to_message_id": self.message_id,
|
|
558
|
+
**kwargs
|
|
559
|
+
})
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
def reply_document(
|
|
563
|
+
self,
|
|
564
|
+
path: Optional[Union[str, Path]] = None,
|
|
565
|
+
file_id: Optional[str] = None,
|
|
566
|
+
text: Optional[str] = None,
|
|
567
|
+
chat_keypad: Optional[Dict[str, Any]] = None,
|
|
568
|
+
inline_keypad: Optional[Dict[str, Any]] = None,
|
|
569
|
+
chat_keypad_type: Optional[str] = "None",
|
|
570
|
+
disable_notification: bool = False
|
|
571
|
+
):
|
|
572
|
+
if chat_keypad and chat_keypad_type == "none":chat_keypad_type == "New"
|
|
573
|
+
return self.bot.send_document(
|
|
574
|
+
chat_id=self.chat_id,
|
|
575
|
+
path=path,
|
|
576
|
+
file_id=file_id,
|
|
577
|
+
text=text,
|
|
578
|
+
chat_keypad=chat_keypad,
|
|
579
|
+
inline_keypad=inline_keypad,
|
|
580
|
+
chat_keypad_type=chat_keypad_type,
|
|
581
|
+
disable_notification=disable_notification,
|
|
582
|
+
reply_to_message_id=self.message_id
|
|
583
|
+
)
|
|
584
|
+
def reply_file(
|
|
585
|
+
self,
|
|
586
|
+
path: Optional[Union[str, Path]] = None,
|
|
587
|
+
file_id: Optional[str] = None,
|
|
588
|
+
text: Optional[str] = None,
|
|
589
|
+
chat_keypad: Optional[Dict[str, Any]] = None,
|
|
590
|
+
inline_keypad: Optional[Dict[str, Any]] = None,
|
|
591
|
+
chat_keypad_type: Optional[str] = "None",
|
|
592
|
+
disable_notification: bool = False
|
|
593
|
+
):
|
|
594
|
+
if chat_keypad and chat_keypad_type == "none":
|
|
595
|
+
chat_keypad_type == "New"
|
|
596
|
+
|
|
597
|
+
return self.bot.send_document(
|
|
598
|
+
chat_id=self.chat_id,
|
|
599
|
+
path=path,
|
|
600
|
+
file_id=file_id,
|
|
601
|
+
text=text,
|
|
602
|
+
chat_keypad=chat_keypad,
|
|
603
|
+
inline_keypad=inline_keypad,
|
|
604
|
+
chat_keypad_type=chat_keypad_type,
|
|
605
|
+
disable_notification=disable_notification,
|
|
606
|
+
reply_to_message_id=self.message_id
|
|
607
|
+
)
|
|
608
|
+
|
|
609
|
+
def reply_image(
|
|
610
|
+
self,
|
|
611
|
+
path: Optional[Union[str, Path]] = None,
|
|
612
|
+
file_id: Optional[str] = None,
|
|
613
|
+
text: Optional[str] = None,
|
|
614
|
+
chat_keypad: Optional[Dict[str, Any]] = None,
|
|
615
|
+
inline_keypad: Optional[Dict[str, Any]] = None,
|
|
616
|
+
chat_keypad_type: Optional[str] = "None",
|
|
617
|
+
disable_notification: bool = False
|
|
618
|
+
):
|
|
619
|
+
if chat_keypad and chat_keypad_type == "none":
|
|
620
|
+
chat_keypad_type == "New"
|
|
621
|
+
return self.bot.send_image(
|
|
622
|
+
chat_id=self.chat_id,
|
|
623
|
+
path=path,
|
|
624
|
+
file_id=file_id,
|
|
625
|
+
text=text,
|
|
626
|
+
chat_keypad=chat_keypad,
|
|
627
|
+
inline_keypad=inline_keypad,
|
|
628
|
+
chat_keypad_type=chat_keypad_type,
|
|
629
|
+
disable_notification=disable_notification,
|
|
630
|
+
reply_to_message_id=self.message_id
|
|
631
|
+
)
|
|
632
|
+
|
|
633
|
+
def reply_music(
|
|
634
|
+
self,
|
|
635
|
+
path: Optional[Union[str, Path]] = None,
|
|
636
|
+
file_id: Optional[str] = None,
|
|
637
|
+
text: Optional[str] = None,
|
|
638
|
+
chat_keypad: Optional[Dict[str, Any]] = None,
|
|
639
|
+
inline_keypad: Optional[Dict[str, Any]] = None,
|
|
640
|
+
chat_keypad_type: Optional[str] = "None",
|
|
641
|
+
disable_notification: bool = False
|
|
642
|
+
):
|
|
643
|
+
if chat_keypad and chat_keypad_type == "none":
|
|
644
|
+
chat_keypad_type == "New"
|
|
645
|
+
return self.bot.send_music(
|
|
646
|
+
chat_id=self.chat_id,
|
|
647
|
+
path=path,
|
|
648
|
+
file_id=file_id,
|
|
649
|
+
text=text,
|
|
650
|
+
chat_keypad=chat_keypad,
|
|
651
|
+
inline_keypad=inline_keypad,
|
|
652
|
+
chat_keypad_type=chat_keypad_type,
|
|
653
|
+
disable_notification=disable_notification,
|
|
654
|
+
reply_to_message_id=self.message_id
|
|
655
|
+
)
|
|
656
|
+
|
|
657
|
+
def reply_voice(
|
|
658
|
+
self,
|
|
659
|
+
path: Optional[Union[str, Path]] = None,
|
|
660
|
+
file_id: Optional[str] = None,
|
|
661
|
+
text: Optional[str] = None,
|
|
662
|
+
chat_keypad: Optional[Dict[str, Any]] = None,
|
|
663
|
+
inline_keypad: Optional[Dict[str, Any]] = None,
|
|
664
|
+
chat_keypad_type: Optional[str] = "None",
|
|
665
|
+
disable_notification: bool = False
|
|
666
|
+
):
|
|
667
|
+
if chat_keypad and chat_keypad_type == "none":
|
|
668
|
+
chat_keypad_type == "New"
|
|
669
|
+
return self.bot.send_voice(
|
|
670
|
+
chat_id=self.chat_id,
|
|
671
|
+
path=path,
|
|
672
|
+
file_id=file_id,
|
|
673
|
+
text=text,
|
|
674
|
+
chat_keypad=chat_keypad,
|
|
675
|
+
inline_keypad=inline_keypad,
|
|
676
|
+
chat_keypad_type=chat_keypad_type,
|
|
677
|
+
disable_notification=disable_notification,
|
|
678
|
+
reply_to_message_id=self.message_id
|
|
679
|
+
)
|
|
680
|
+
|
|
681
|
+
def reply_gif(
|
|
682
|
+
self,
|
|
683
|
+
path: Optional[Union[str, Path]] = None,
|
|
684
|
+
file_id: Optional[str] = None,
|
|
685
|
+
text: Optional[str] = None,
|
|
686
|
+
chat_keypad: Optional[Dict[str, Any]] = None,
|
|
687
|
+
inline_keypad: Optional[Dict[str, Any]] = None,
|
|
688
|
+
chat_keypad_type: Optional[str] = "None",
|
|
689
|
+
disable_notification: bool = False
|
|
690
|
+
):
|
|
691
|
+
if chat_keypad and chat_keypad_type == "none":chat_keypad_type == "New"
|
|
692
|
+
return self.bot.send_gif(
|
|
693
|
+
chat_id=self.chat_id,
|
|
694
|
+
path=path,
|
|
695
|
+
file_id=file_id,
|
|
696
|
+
text=text,
|
|
697
|
+
chat_keypad=chat_keypad,
|
|
698
|
+
inline_keypad=inline_keypad,
|
|
699
|
+
chat_keypad_type=chat_keypad_type,
|
|
700
|
+
disable_notification=disable_notification,
|
|
701
|
+
reply_to_message_id=self.message_id
|
|
702
|
+
)
|
|
703
|
+
|
|
704
|
+
def reply_location(self, latitude: str, longitude: str, **kwargs) -> Dict[str, Any]:
|
|
705
|
+
return self.bot.send_location(
|
|
706
|
+
chat_id=self.chat_id,
|
|
707
|
+
latitude=latitude,
|
|
708
|
+
longitude=longitude,
|
|
709
|
+
reply_to_message_id=self.message_id,
|
|
710
|
+
**kwargs
|
|
711
|
+
)
|
|
712
|
+
|
|
713
|
+
def reply_contact(self, first_name: str, last_name: str, phone_number: str, **kwargs) -> Dict[str, Any]:
|
|
714
|
+
return self.bot.send_contact(
|
|
715
|
+
chat_id=self.chat_id,
|
|
716
|
+
first_name=first_name,
|
|
717
|
+
last_name=last_name,
|
|
718
|
+
phone_number=phone_number,
|
|
719
|
+
reply_to_message_id=self.message_id,
|
|
720
|
+
**kwargs
|
|
721
|
+
)
|
|
722
|
+
|
|
723
|
+
def reply_keypad(self, text: str, keypad: Dict[str, Any], **kwargs) -> Dict[str, Any]:
|
|
724
|
+
return self.bot.send_message(
|
|
725
|
+
chat_id=self.chat_id,
|
|
726
|
+
text=text,
|
|
727
|
+
chat_keypad_type="New",
|
|
728
|
+
chat_keypad=keypad,
|
|
729
|
+
reply_to_message_id=self.message_id,
|
|
730
|
+
**kwargs
|
|
731
|
+
)
|
|
732
|
+
|
|
733
|
+
def reply_inline(self, text: str, inline_keypad: Dict[str, Any], **kwargs) -> Dict[str, Any]:
|
|
734
|
+
return self.bot.send_message(
|
|
735
|
+
chat_id=self.chat_id,
|
|
736
|
+
text=text,
|
|
737
|
+
inline_keypad=inline_keypad,
|
|
738
|
+
reply_to_message_id=self.message_id,
|
|
739
|
+
**kwargs
|
|
740
|
+
)
|
|
741
|
+
|
|
742
|
+
def reply_sticker(self, sticker_id: str, **kwargs) -> Dict[str, Any]:
|
|
743
|
+
return self.bot._post("sendSticker", {
|
|
744
|
+
"chat_id": self.chat_id,
|
|
745
|
+
"sticker_id": sticker_id,
|
|
746
|
+
"reply_to_message_id": self.message_id,
|
|
747
|
+
**kwargs
|
|
748
|
+
})
|
|
749
|
+
|
|
750
|
+
def edit(self, new_text: str) -> Dict[str, Any]:
|
|
554
751
|
return self.bot.edit_message_text(
|
|
555
752
|
chat_id=self.chat_id,
|
|
556
753
|
message_id=self.message_id,
|
|
557
754
|
text=new_text
|
|
558
755
|
)
|
|
559
756
|
|
|
560
|
-
def delete(self):
|
|
757
|
+
def delete(self) -> Dict[str, Any]:
|
|
561
758
|
return self.bot.delete_message(
|
|
562
759
|
chat_id=self.chat_id,
|
|
563
760
|
message_id=self.message_id
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: Rubka
|
|
3
|
-
Version: 6.
|
|
3
|
+
Version: 6.7.1
|
|
4
4
|
Summary: rubika A Python library for interacting with Rubika Bot API.
|
|
5
5
|
Home-page: https://github.com/Mahdy-Ahmadi/Rubka
|
|
6
6
|
Download-URL: https://github.com/Mahdy-Ahmadi/rubka/archive/refs/tags/v6.6.4.zip
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
rubka/__init__.py,sha256=P6IBiORfp-GqKHe5LZ-5lldWyG7tnrUYUcAQDUgwXmY,1973
|
|
2
2
|
rubka/api.py,sha256=1S8JIcYN_Zxb7JT73eQl9me-qDDDTDzcSk6_qawAfkA,68861
|
|
3
|
-
rubka/asynco.py,sha256=
|
|
3
|
+
rubka/asynco.py,sha256=QRieOUl4w81zP-a2FtbLmI9DuExy9d6m1jDR4RUhuo4,100228
|
|
4
4
|
rubka/button.py,sha256=vU9OvWXCD4MRrTJ8Xmivd4L471-06zrD2qpZBTw5vjY,13305
|
|
5
5
|
rubka/config.py,sha256=Bck59xkOiqioLv0GkQ1qPGnBXVctz1hKk6LT4h2EPx0,78
|
|
6
|
-
rubka/context.py,sha256=
|
|
6
|
+
rubka/context.py,sha256=kYLsGq4cQhmMX16WrzH_kxYzGGyvulZyxazoN_5tul4,30768
|
|
7
7
|
rubka/decorators.py,sha256=hGwUoE4q2ImrunJIGJ_kzGYYxQf1ueE0isadqraKEts,1157
|
|
8
|
-
rubka/exceptions.py,sha256=
|
|
8
|
+
rubka/exceptions.py,sha256=DDOGIHEMoliHNW5E7C_s38WZgqqMBv9812fcJGvj7TY,1173
|
|
9
9
|
rubka/filters.py,sha256=DY1bdkpRKIiLtVcy6X3hOnlGPcVOK4HFb3QgmaPx6Oo,12116
|
|
10
10
|
rubka/helpers.py,sha256=QvK5lg4QDmycImxJia4m8HDpfacYzbKKZiOk536mafc,65161
|
|
11
11
|
rubka/jobs.py,sha256=GvLMLsVhcSEzRTgkvnPISPEBN71suW2xXI0hUaUZPTo,378
|
|
@@ -14,7 +14,7 @@ rubka/keypad.py,sha256=yGsNt8W5HtUFBzVF1m_p7GySlu1hwIcSvXZ4BTdrlvg,9558
|
|
|
14
14
|
rubka/logger.py,sha256=J2I6NiK1z32lrAzC4H1Et6WPMBXxXGCVUsW4jgcAofs,289
|
|
15
15
|
rubka/rubino.py,sha256=GuXnEUTTSZUw68FMTQBYsB2zG_3rzdDa-krsrl4ib8w,58755
|
|
16
16
|
rubka/tv.py,sha256=o7CW-6EKLhmM--rzcHcKPcXfzOixcL_B4j037R3mHts,5399
|
|
17
|
-
rubka/update.py,sha256=
|
|
17
|
+
rubka/update.py,sha256=kYLsGq4cQhmMX16WrzH_kxYzGGyvulZyxazoN_5tul4,30768
|
|
18
18
|
rubka/utils.py,sha256=XUQUZxQt9J2f0X5hmAH_MH1kibTAfdT1T4AaBkBhBBs,148
|
|
19
19
|
rubka/adaptorrubka/__init__.py,sha256=6o2tCXnVeES7nx-LjnzsuMqjKcWIm9qwKficLE54s-U,83
|
|
20
20
|
rubka/adaptorrubka/enums.py,sha256=cyiakExmZi-QQpYuf_A93HQvfZVmyG_0uVuvTTNT5To,1053
|
|
@@ -37,8 +37,8 @@ rubka/adaptorrubka/types/socket/message.py,sha256=0WgLMZh4eow8Zn7AiSX4C3GZjQTkIg
|
|
|
37
37
|
rubka/adaptorrubka/utils/__init__.py,sha256=OgCFkXdNFh379quNwIVOAWY2NP5cIOxU5gDRRALTk4o,54
|
|
38
38
|
rubka/adaptorrubka/utils/configs.py,sha256=nMUEOJh1NqDJsf9W9PurkN_DLYjO6kKPMm923i4Jj_A,492
|
|
39
39
|
rubka/adaptorrubka/utils/utils.py,sha256=5-LioLNYX_TIbQGDeT50j7Sg9nAWH2LJUUs-iEXpsUY,8816
|
|
40
|
-
rubka-6.
|
|
41
|
-
rubka-6.
|
|
42
|
-
rubka-6.
|
|
43
|
-
rubka-6.
|
|
44
|
-
rubka-6.
|
|
40
|
+
rubka-6.7.1.dist-info/METADATA,sha256=EWh4ebJjsnf3NgzY03qEjhZbuQhQ54GfljbLr7WNTnM,34269
|
|
41
|
+
rubka-6.7.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
42
|
+
rubka-6.7.1.dist-info/entry_points.txt,sha256=4aESuUmuUOALMUy7Kucv_Gb5YlqhsJmTmdXLlZU9sJ0,46
|
|
43
|
+
rubka-6.7.1.dist-info/top_level.txt,sha256=vy2A4lot11cRMdQS-F4HDCIXL3JK8RKfu7HMDkezJW4,6
|
|
44
|
+
rubka-6.7.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|