Rubka 4.5.11__py3-none-any.whl → 4.6.0__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/api.py +1 -1
- rubka/asynco.py +56 -24
- rubka/context.py +41 -14
- {rubka-4.5.11.dist-info → rubka-4.6.0.dist-info}/METADATA +6 -1
- {rubka-4.5.11.dist-info → rubka-4.6.0.dist-info}/RECORD +7 -7
- {rubka-4.5.11.dist-info → rubka-4.6.0.dist-info}/WHEEL +0 -0
- {rubka-4.5.11.dist-info → rubka-4.6.0.dist-info}/top_level.txt +0 -0
rubka/api.py
CHANGED
rubka/asynco.py
CHANGED
|
@@ -90,8 +90,8 @@ async def check_rubka_version():
|
|
|
90
90
|
print("Not updating may lead to malfunctions or incompatibility.")
|
|
91
91
|
print("To see new methods : @rubka_library\n\n")
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
|
|
94
|
+
|
|
95
95
|
|
|
96
96
|
def show_last_six_words(text: str) -> str:
|
|
97
97
|
"""Returns the last 6 characters of a stripped string."""
|
|
@@ -226,7 +226,39 @@ class Robot:
|
|
|
226
226
|
})
|
|
227
227
|
return func
|
|
228
228
|
return decorator
|
|
229
|
+
def on_inline_query_prefix(self, prefix: str, button_id: Optional[str] = None):
|
|
230
|
+
if not prefix.startswith('/'):
|
|
231
|
+
prefix = '/' + prefix
|
|
232
|
+
|
|
233
|
+
def decorator(func: Callable[[Any, InlineMessage], None]):
|
|
234
|
+
|
|
235
|
+
async def handler_wrapper(bot_instance, inline_message: InlineMessage):
|
|
236
|
+
|
|
237
|
+
if not inline_message.raw_data or 'text' not in inline_message.raw_data:
|
|
238
|
+
return
|
|
229
239
|
|
|
240
|
+
query_text = inline_message.raw_data['text']
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
if query_text.startswith(prefix):
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
try:
|
|
248
|
+
await func(bot_instance, inline_message)
|
|
249
|
+
except Exception as e:
|
|
250
|
+
print(f"Error in inline query prefix handler '{prefix}': {e}")
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
self._inline_query_handlers.append({
|
|
254
|
+
"func": handler_wrapper,
|
|
255
|
+
"button_id": button_id
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
})
|
|
260
|
+
return func
|
|
261
|
+
return decorator
|
|
230
262
|
async def _process_update(self, update: dict):
|
|
231
263
|
if update.get("type") == "ReceiveQuery":
|
|
232
264
|
msg = update.get("inline_message", {})
|
|
@@ -249,40 +281,40 @@ class Robot:
|
|
|
249
281
|
text=msg.get("text"),
|
|
250
282
|
raw_data=msg)
|
|
251
283
|
|
|
252
|
-
|
|
284
|
+
|
|
253
285
|
if context.aux_data and self._callback_handlers:
|
|
254
286
|
for handler in self._callback_handlers:
|
|
255
287
|
if not handler["button_id"] or context.aux_data.button_id == handler["button_id"]:
|
|
256
288
|
asyncio.create_task(handler["func"](self, context))
|
|
257
289
|
return
|
|
258
290
|
|
|
259
|
-
|
|
291
|
+
|
|
260
292
|
if self._message_handlers:
|
|
261
293
|
for handler_info in self._message_handlers:
|
|
262
|
-
|
|
294
|
+
|
|
263
295
|
if handler_info["commands"]:
|
|
264
296
|
if not context.text or not context.text.startswith("/"):
|
|
265
|
-
continue
|
|
297
|
+
continue
|
|
266
298
|
parts = context.text.split()
|
|
267
299
|
cmd = parts[0][1:]
|
|
268
300
|
if cmd not in handler_info["commands"]:
|
|
269
|
-
continue
|
|
301
|
+
continue
|
|
270
302
|
context.args = parts[1:]
|
|
271
303
|
|
|
272
|
-
|
|
304
|
+
|
|
273
305
|
if handler_info["filters"]:
|
|
274
306
|
if not handler_info["filters"](context):
|
|
275
|
-
continue
|
|
307
|
+
continue
|
|
308
|
+
|
|
276
309
|
|
|
277
|
-
# اگر هندلری برای همه پیامها باشد (بدون کامند و فیلتر)
|
|
278
310
|
if not handler_info["commands"] and not handler_info["filters"]:
|
|
279
311
|
asyncio.create_task(handler_info["func"](self, context))
|
|
280
|
-
return
|
|
312
|
+
return
|
|
313
|
+
|
|
281
314
|
|
|
282
|
-
# اگر شرایط کامند یا فیلتر برقرار بود
|
|
283
315
|
if handler_info["commands"] or handler_info["filters"]:
|
|
284
316
|
asyncio.create_task(handler_info["func"](self, context))
|
|
285
|
-
return
|
|
317
|
+
return
|
|
286
318
|
|
|
287
319
|
async def get_updates(self, offset_id: Optional[str] = None, limit: Optional[int] = None) -> Dict[str, Any]:
|
|
288
320
|
data = {}
|
|
@@ -297,7 +329,7 @@ class Robot:
|
|
|
297
329
|
if limit: params['limit'] = limit
|
|
298
330
|
async with session.get(self.web_hook, params=params) as response:
|
|
299
331
|
response.raise_for_status()
|
|
300
|
-
|
|
332
|
+
|
|
301
333
|
return await response.json()
|
|
302
334
|
|
|
303
335
|
def _is_duplicate(self, message_id: str, max_age_sec: int = 300) -> bool:
|
|
@@ -326,8 +358,8 @@ class Robot:
|
|
|
326
358
|
while True:
|
|
327
359
|
try:
|
|
328
360
|
if self.web_hook:
|
|
329
|
-
|
|
330
|
-
|
|
361
|
+
|
|
362
|
+
|
|
331
363
|
webhook_data = await self.update_webhook()
|
|
332
364
|
if isinstance(webhook_data, list):
|
|
333
365
|
for item in webhook_data:
|
|
@@ -340,7 +372,7 @@ class Robot:
|
|
|
340
372
|
if time.time() - received_at_ts > 20:
|
|
341
373
|
continue
|
|
342
374
|
except (ValueError, TypeError):
|
|
343
|
-
pass
|
|
375
|
+
pass
|
|
344
376
|
|
|
345
377
|
update = None
|
|
346
378
|
if "update" in data:
|
|
@@ -358,11 +390,11 @@ class Robot:
|
|
|
358
390
|
elif "message_id" in update:
|
|
359
391
|
message_id = update.get("message_id")
|
|
360
392
|
|
|
361
|
-
if message_id and not self._is_duplicate(str(
|
|
393
|
+
if message_id and not self._is_duplicate(str(received_at_str)):
|
|
362
394
|
await self._process_update(update)
|
|
363
395
|
|
|
364
396
|
else:
|
|
365
|
-
|
|
397
|
+
|
|
366
398
|
get_updates_response = await self.get_updates(offset_id=self._offset_id, limit=100)
|
|
367
399
|
if get_updates_response and get_updates_response.get("data"):
|
|
368
400
|
updates = get_updates_response["data"].get("updates", [])
|
|
@@ -380,10 +412,10 @@ class Robot:
|
|
|
380
412
|
if message_id and not self._is_duplicate(str(message_id)):
|
|
381
413
|
await self._process_update(update)
|
|
382
414
|
|
|
383
|
-
await asyncio.sleep(0
|
|
415
|
+
await asyncio.sleep(0)
|
|
384
416
|
except Exception as e:
|
|
385
417
|
print(f"❌ Error in run loop: {e}")
|
|
386
|
-
await asyncio.sleep(5)
|
|
418
|
+
await asyncio.sleep(5)
|
|
387
419
|
finally:
|
|
388
420
|
if self._aiohttp_session:
|
|
389
421
|
await self._aiohttp_session.close()
|
|
@@ -438,7 +470,7 @@ class Robot:
|
|
|
438
470
|
username = chat_info.get('username')
|
|
439
471
|
user_id = chat_info.get('user_id')
|
|
440
472
|
|
|
441
|
-
|
|
473
|
+
|
|
442
474
|
if username:
|
|
443
475
|
result = await asyncio.to_thread(self.get_all_member, channel_guid, search_text=username)
|
|
444
476
|
members = result.get('in_chat_members', [])
|
|
@@ -449,7 +481,7 @@ class Robot:
|
|
|
449
481
|
return False
|
|
450
482
|
|
|
451
483
|
def get_all_member(self, channel_guid: str, search_text: str = None, start_id: str = None, just_get_guids: bool = False):
|
|
452
|
-
|
|
484
|
+
|
|
453
485
|
client = self._get_client()
|
|
454
486
|
return client.get_all_members(channel_guid, search_text, start_id, just_get_guids)
|
|
455
487
|
|
|
@@ -639,7 +671,7 @@ class Robot:
|
|
|
639
671
|
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)
|
|
640
672
|
|
|
641
673
|
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]:
|
|
642
|
-
return await self._send_file_generic("
|
|
674
|
+
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)
|
|
643
675
|
|
|
644
676
|
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]:
|
|
645
677
|
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)
|
rubka/context.py
CHANGED
|
@@ -14,9 +14,9 @@ class Sticker:
|
|
|
14
14
|
self.file = File(data.get("file", {}))
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
20
|
class PollStatus:
|
|
21
21
|
def __init__(self, data: dict):
|
|
22
22
|
self.state: str = data.get("state")
|
|
@@ -33,9 +33,9 @@ class Poll:
|
|
|
33
33
|
self.poll_status = PollStatus(data.get("poll_status", {}))
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
39
|
class Location:
|
|
40
40
|
def __init__(self, data: dict):
|
|
41
41
|
self.latitude: str = data.get("latitude")
|
|
@@ -67,18 +67,18 @@ class ForwardedFrom:
|
|
|
67
67
|
self.from_sender_id: str = data.get("from_sender_id")
|
|
68
68
|
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
73
|
class AuxData:
|
|
74
74
|
def __init__(self, data: dict):
|
|
75
75
|
self.start_id: str = data.get("start_id")
|
|
76
76
|
self.button_id: str = data.get("button_id")
|
|
77
77
|
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
82
|
class ButtonTextbox:
|
|
83
83
|
def __init__(self, data: dict):
|
|
84
84
|
self.type_line: str = data.get("type_line")
|
|
@@ -221,6 +221,13 @@ class Message:
|
|
|
221
221
|
reply_to_message_id=self.message_id,
|
|
222
222
|
**kwargs
|
|
223
223
|
)
|
|
224
|
+
def answer(self, text: str, **kwargs):
|
|
225
|
+
return self.bot.send_message(
|
|
226
|
+
self.chat_id,
|
|
227
|
+
text,
|
|
228
|
+
reply_to_message_id=self.message_id,
|
|
229
|
+
**kwargs
|
|
230
|
+
)
|
|
224
231
|
|
|
225
232
|
def reply_poll(self, question: str, options: List[str], **kwargs) -> Dict[str, Any]:
|
|
226
233
|
return self.bot._post("sendPoll", {
|
|
@@ -437,12 +444,25 @@ class AuxData:
|
|
|
437
444
|
self.start_id = data.get("start_id")
|
|
438
445
|
self.button_id = data.get("button_id")
|
|
439
446
|
|
|
440
|
-
|
|
447
|
+
|
|
441
448
|
class InlineMessage:
|
|
442
449
|
def __init__(self, bot, raw_data: dict):
|
|
443
450
|
self.bot = bot
|
|
444
451
|
self.raw_data = raw_data
|
|
445
|
-
|
|
452
|
+
self.chat_id = self.raw_data.get("chat_id")
|
|
453
|
+
self.time: str = self.raw_data.get("time")
|
|
454
|
+
self.is_edited: bool = self.raw_data.get("is_edited", False)
|
|
455
|
+
self.sender_type: str = self.raw_data.get("sender_type")
|
|
456
|
+
self.args = []
|
|
457
|
+
self.reply_to_message_id: Optional[str] = self.raw_data.get("reply_to_message_id")
|
|
458
|
+
self.forwarded_from = ForwardedFrom(self.raw_data["forwarded_from"]) if "forwarded_from" in self.raw_data else None
|
|
459
|
+
self.file = File(self.raw_data["file"]) if "file" in self.raw_data else None
|
|
460
|
+
self.sticker = Sticker(self.raw_data["sticker"]) if "sticker" in self.raw_data else None
|
|
461
|
+
self.contact_message = ContactMessage(self.raw_data["contact_message"]) if "contact_message" in self.raw_data else None
|
|
462
|
+
self.poll = Poll(self.raw_data["poll"]) if "poll" in self.raw_data else None
|
|
463
|
+
self.location = Location(self.raw_data["location"]) if "location" in self.raw_data else None
|
|
464
|
+
self.live_location = LiveLocation(self.raw_data["live_location"]) if "live_location" in self.raw_data else None
|
|
465
|
+
self.aux_data = AuxData(self.raw_data["aux_data"]) if "aux_data" in self.raw_data else None
|
|
446
466
|
self.chat_id: str = raw_data.get("chat_id")
|
|
447
467
|
self.message_id: str = raw_data.get("message_id")
|
|
448
468
|
self.sender_id: str = raw_data.get("sender_id")
|
|
@@ -456,6 +476,13 @@ class InlineMessage:
|
|
|
456
476
|
reply_to_message_id=self.message_id,
|
|
457
477
|
**kwargs
|
|
458
478
|
)
|
|
479
|
+
def answer(self, text: str, **kwargs):
|
|
480
|
+
return self.bot.send_message(
|
|
481
|
+
self.chat_id,
|
|
482
|
+
text,
|
|
483
|
+
reply_to_message_id=self.message_id,
|
|
484
|
+
**kwargs
|
|
485
|
+
)
|
|
459
486
|
|
|
460
487
|
def edit(self, new_text: str):
|
|
461
488
|
return self.bot.edit_message_text(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: Rubka
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.6.0
|
|
4
4
|
Summary: 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/blob/main/project_library.zip
|
|
@@ -19,6 +19,11 @@ Requires-Dist: requests
|
|
|
19
19
|
Requires-Dist: Pillow
|
|
20
20
|
Requires-Dist: websocket-client
|
|
21
21
|
Requires-Dist: pycryptodome
|
|
22
|
+
Requires-Dist: aiohttp
|
|
23
|
+
Requires-Dist: tqdm
|
|
24
|
+
Requires-Dist: mutagen
|
|
25
|
+
Requires-Dist: filetype
|
|
26
|
+
Requires-Dist: aiofiles
|
|
22
27
|
Dynamic: author
|
|
23
28
|
Dynamic: author-email
|
|
24
29
|
Dynamic: classifier
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
rubka/__init__.py,sha256=TR1DABU5Maz2eO62ZEFiwOqNU0dH6l6HZfqRUxeo4eY,194
|
|
2
|
-
rubka/api.py,sha256
|
|
3
|
-
rubka/asynco.py,sha256=
|
|
2
|
+
rubka/api.py,sha256=-ayu17rFI35hU1O7ePxLQNTK-upj2uJxOflA0JUdWdI,39421
|
|
3
|
+
rubka/asynco.py,sha256=f2OH2JDdB98x7T4c6B1n-dTWpCe8R5KkkHUdwr9IP9g,37433
|
|
4
4
|
rubka/button.py,sha256=4fMSZR7vUADxSmw1R3_pZ4dw5uMLZX5sOkwPPyNTBDE,8437
|
|
5
5
|
rubka/config.py,sha256=Bck59xkOiqioLv0GkQ1qPGnBXVctz1hKk6LT4h2EPx0,78
|
|
6
|
-
rubka/context.py,sha256=
|
|
6
|
+
rubka/context.py,sha256=jtdMYf2slFxK2kmkVO6MMSTl-yu5NH52UvzAOyB79hw,19317
|
|
7
7
|
rubka/decorators.py,sha256=hGwUoE4q2ImrunJIGJ_kzGYYxQf1ueE0isadqraKEts,1157
|
|
8
8
|
rubka/exceptions.py,sha256=tujZt1XrhWaw-lmdeVadVceUptpw4XzNgE44sAAY0gs,90
|
|
9
9
|
rubka/jobs.py,sha256=GvLMLsVhcSEzRTgkvnPISPEBN71suW2xXI0hUaUZPTo,378
|
|
@@ -33,7 +33,7 @@ rubka/adaptorrubka/types/socket/message.py,sha256=0WgLMZh4eow8Zn7AiSX4C3GZjQTkIg
|
|
|
33
33
|
rubka/adaptorrubka/utils/__init__.py,sha256=OgCFkXdNFh379quNwIVOAWY2NP5cIOxU5gDRRALTk4o,54
|
|
34
34
|
rubka/adaptorrubka/utils/configs.py,sha256=nMUEOJh1NqDJsf9W9PurkN_DLYjO6kKPMm923i4Jj_A,492
|
|
35
35
|
rubka/adaptorrubka/utils/utils.py,sha256=5-LioLNYX_TIbQGDeT50j7Sg9nAWH2LJUUs-iEXpsUY,8816
|
|
36
|
-
rubka-4.
|
|
37
|
-
rubka-4.
|
|
38
|
-
rubka-4.
|
|
39
|
-
rubka-4.
|
|
36
|
+
rubka-4.6.0.dist-info/METADATA,sha256=ZSH799BnofV3TFaXKdi_unkoru9Yki1Sbv3L1upObMI,33335
|
|
37
|
+
rubka-4.6.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
38
|
+
rubka-4.6.0.dist-info/top_level.txt,sha256=vy2A4lot11cRMdQS-F4HDCIXL3JK8RKfu7HMDkezJW4,6
|
|
39
|
+
rubka-4.6.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|