pyrobale 0.3.8__py3-none-any.whl → 0.3.9__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.
@@ -37,13 +37,16 @@ from ..objects.voice import Voice
37
37
  from ..objects.webappdata import WebAppData
38
38
  from ..objects.webappinfo import WebAppInfo
39
39
  from ..objects.utils import *
40
- import asyncio
41
- from enum import Enum
42
40
  from ..objects.enums import UpdatesTypes, ChatAction, ChatType
41
+ from ..objects.peerdata import PeerData
43
42
  from ..filters import Filters, equals
44
43
  from ..StateMachine import StateMachine
45
44
  from ..exceptions import NotFoundException, InvalidTokenException, PyroBaleException
46
45
 
46
+ from enum import Enum
47
+ import asyncio
48
+ from bs4 import BeautifulSoup
49
+ from json import loads, JSONDecodeError
47
50
 
48
51
  class Client:
49
52
  """A client for interacting with the Bale messenger API.
@@ -64,6 +67,9 @@ class Client:
64
67
  self.last_update_id = 0
65
68
  self.state_machine = StateMachine()
66
69
 
70
+ self.check_defined_message = True
71
+ self.defined_messages = {}
72
+
67
73
  async def get_updates(
68
74
  self,
69
75
  offset: Optional[int] = None,
@@ -695,6 +701,22 @@ class Client:
695
701
  self.requests_base + "/leaveChat", data={"chat_id": chat_id}
696
702
  )
697
703
  return data.get("ok", False)
704
+
705
+ async def is_joined(self, user_id: int, chat_id: int) -> bool:
706
+ """Check if a user is joined to a chat.
707
+
708
+ Args:
709
+ user_id (int): Unique identifier for the target chat
710
+ chat_id (int): Unique identifier for the target chat
711
+
712
+ Returns:
713
+ bool: True if the user is joined to the chat, False otherwise
714
+ """
715
+ data = await make_post(
716
+ self.requests_base + "/getChatMember",
717
+ data={"chat_id": chat_id, "user_id": user_id},
718
+ )
719
+ return data.get("result", {}).get("status") in ["member", "creator", "administrator"]
698
720
 
699
721
  async def get_chat(self, chat_id: int) -> Chat:
700
722
  """Get up to date information about the chat.
@@ -709,7 +731,100 @@ class Client:
709
731
  self.requests_base + "/getChat", data={"chat_id": chat_id}
710
732
  )
711
733
  return Chat(**pythonize(data["result"]))
712
-
734
+
735
+ @staticmethod
736
+ async def get_ble_ir_page(username_or_phone_number: str) -> Union[dict, PeerData]:
737
+ """Get BleIR user/group information.
738
+
739
+ Args:
740
+ username_or_phone_number (str): Username or phone number
741
+
742
+ Returns:
743
+ Union[dict, PeerData]: User/group information or error dict
744
+ """
745
+ url = f"https://ble.ir/{username_or_phone_number}"
746
+
747
+ async with aiohttp.ClientSession() as session:
748
+ async with session.get(url) as response:
749
+ req = await response.text()
750
+
751
+ if """<p class="__404_title__lxIKL">گفتگوی مورد نظر وجود ندارد.</p>""" in req:
752
+ return PeerData(
753
+ is_ok=False,
754
+ avatar=None,
755
+ description=None,
756
+ name=None,
757
+ is_bot=None,
758
+ is_verified=None,
759
+ is_private=None,
760
+ members=None,
761
+ last_message=None,
762
+ user_id=None,
763
+ username=None,
764
+ )
765
+
766
+ soup = BeautifulSoup(req, "html.parser")
767
+ json_data = {}
768
+
769
+ try:
770
+ json_script = soup.find("script", id="__NEXT_DATA__").text
771
+ json_data = loads(json_script)
772
+ page_props = json_data.get("props", {}).get("pageProps", {})
773
+ user_data = page_props.get("user", {})
774
+ group_data = page_props.get("group", {})
775
+ messages = page_props.get("messages", [])
776
+ except (AttributeError, KeyError, JSONDecodeError):
777
+ pass
778
+
779
+ try:
780
+ avatar = soup.find("img", class_="Avatar_img___C2_3")["src"]
781
+ except (AttributeError, KeyError):
782
+ avatar = None
783
+
784
+ try:
785
+ description = soup.find("div", class_="Profile_description__YTAr_").text
786
+ except AttributeError:
787
+ description = None
788
+
789
+ try:
790
+ name = soup.find("h1", class_="Profile_name__pQglx").text
791
+ except AttributeError:
792
+ name = None
793
+
794
+ is_bot = user_data.get("isBot", False)
795
+ is_verified = user_data.get("isVerified", group_data.get("isVerified", False))
796
+ is_private = user_data.get("isPrivate", group_data.get("isPrivate", False))
797
+ members = group_data.get("members")
798
+ username = user_data.get("nick")
799
+ user_id = page_props.get("peer", {}).get("id")
800
+
801
+ last_message = None
802
+ if messages:
803
+ try:
804
+ last_msg = messages[-1]["message"]
805
+ last_message = (
806
+ last_msg.get("documentMessage", {}).get("caption", {}).get("text")
807
+ or last_msg.get("textMessage", {}).get("text")
808
+ )
809
+ if last_message:
810
+ last_message = last_message.replace("&zwnj;", "")
811
+ except (KeyError, IndexError):
812
+ pass
813
+
814
+ return PeerData(
815
+ True,
816
+ avatar,
817
+ description,
818
+ name,
819
+ is_bot,
820
+ is_verified,
821
+ is_private,
822
+ members,
823
+ last_message,
824
+ user_id,
825
+ username
826
+ )
827
+
713
828
  async def get_chat_members_count(self, chat_id: int) -> int:
714
829
  """Get the number of members in a chat.
715
830
 
@@ -925,6 +1040,11 @@ class Client:
925
1040
  if update_id:
926
1041
  self.last_update_id = update_id + 1
927
1042
 
1043
+ if self.check_defined_message:
1044
+ update_raw = update['message']
1045
+ if update_raw.get("text") in self.defined_messages.keys():
1046
+ await self.send_message(update_raw.get('chat').get('id'), self.defined_messages.get(update_raw.get("text")), update.get('message_id'))
1047
+
928
1048
  for waiter in list(self._waiters):
929
1049
  w_type, check, future = waiter
930
1050
  if w_type.value in update:
@@ -940,6 +1060,8 @@ class Client:
940
1060
  update_type = handler["type"].value
941
1061
  if update_type in update:
942
1062
  raw_event = update[update_type]
1063
+
1064
+
943
1065
  event = self._convert_event(handler["type"], raw_event)
944
1066
 
945
1067
  if handler["type"] == UpdatesTypes.COMMAND:
pyrobale/objects/chat.py CHANGED
@@ -386,6 +386,17 @@ class Chat:
386
386
  bool: True on success
387
387
  """
388
388
  return await self.client.leave_chat(chat_id=self.id)
389
+
390
+ async def is_joined(self, user_id: int) -> bool:
391
+ """Check if a user is joined to the chat.
392
+
393
+ Parameters:
394
+ user_id (int): Unique identifier of the target user
395
+
396
+ Returns:
397
+ bool: True if the user is joined to the chat, False otherwise
398
+ """
399
+ return await self.client.is_joined(user_id, self.id)
389
400
 
390
401
  async def pin(self, message_id: int) -> bool:
391
402
  """Pin a message in the chat.
@@ -0,0 +1,25 @@
1
+ class PeerData:
2
+ """A class to parse data received from ble.ir pages."""
3
+ def __init__(self,
4
+ is_ok: bool,
5
+ avatar: str,
6
+ description: str,
7
+ name: str,
8
+ is_bot: bool,
9
+ is_verified: bool,
10
+ is_private: bool,
11
+ members: int,
12
+ last_message: str,
13
+ user_id: int,
14
+ username: str):
15
+ self.is_ok = is_ok
16
+ self.avatar = avatar
17
+ self.description = description
18
+ self.name = name
19
+ self.is_bot = is_bot
20
+ self.is_verified = is_verified
21
+ self.is_private = is_private
22
+ self.members = members
23
+ self.last_message = last_message
24
+ self.user_id = user_id
25
+ self.username = username
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyrobale
3
- Version: 0.3.8
3
+ Version: 0.3.9
4
4
  Summary: A python wrapper for bale api
5
5
  Project-URL: github, https://github.com/pyrobale/pyrobale
6
6
  Project-URL: website, https://pyrobale.github.io
7
- Author-email: Ali Safamanesh <darg.q.a.a@gmail.com>, Aydin Rahbaran <codewizaard9@gmail.com>
7
+ Author-email: Ali Safamanesh <daradege@proton.me>, Aydin Rahbaran <codewizaard9@gmail.com>
8
8
  License: MIT License
9
9
 
10
10
  Copyright (c) 2025 PyroBale Team
@@ -32,6 +32,7 @@ Classifier: Operating System :: OS Independent
32
32
  Classifier: Programming Language :: Python :: 3
33
33
  Requires-Python: >=3.9
34
34
  Requires-Dist: aiohttp
35
+ Requires-Dist: beautifulsoup4
35
36
  Description-Content-Type: text/markdown
36
37
 
37
38
  ![pyrobaletext](https://raw.githubusercontent.com/pyrobale/pyrobale/refs/heads/main/pyrobaletext.png)
@@ -1,6 +1,6 @@
1
1
  pyrobale/__init__.py,sha256=tC4gr6RIg4tYdzoBDFQCU2CDigXytc-MQ7yH6BJzTzM,3651
2
2
  pyrobale/StateMachine/__init__.py,sha256=TRCBwcr4UlnpU2Olik0vOtNASUOK7_O6RMAG6RrVYlM,1911
3
- pyrobale/client/__init__.py,sha256=xl7TyimdjJLLEPmhpRGV_0-JIN8hCPISmYwle7a6eSI,45539
3
+ pyrobale/client/__init__.py,sha256=y_S4MU8nHZ6k77OYR8_ONmscm0EvlvaCpgCWR3ic5wQ,49921
4
4
  pyrobale/exceptions/__init__.py,sha256=oa412OuokRm9Vf3XlCJLqpZjz9ZcuxAKxnEBvOK7u2M,21
5
5
  pyrobale/exceptions/common.py,sha256=6ubWjGNmbRbNuzM_ohPuLvGhLdCiCZ-RscEERnv3JMA,273
6
6
  pyrobale/filters/__init__.py,sha256=Q-VFK1U5W9jMWneAqNLNlYSTZI2gjnAkwA-lcqF9GbU,55
@@ -10,7 +10,7 @@ pyrobale/objects/__init__.py,sha256=uy0xBJc5d-1TnlPD6CgxAaUjBnIvQs-GuAgLeEKoXSQ,
10
10
  pyrobale/objects/animation.py,sha256=jpM9V8AOaGLWkcENTDmsxKf57Abf-MArYBLfU6GwkD0,978
11
11
  pyrobale/objects/audio.py,sha256=q14wz5WpC3SgKZkAlH-D9M554RYQNDwuCT2z7v7IZYU,696
12
12
  pyrobale/objects/callbackquery.py,sha256=jALmTVXU6tc6OppTTrhGERCzugzazYrT39AhhGE-UeI,1018
13
- pyrobale/objects/chat.py,sha256=gQ1wpmB63Ot51aeSBAiWzbw9lFgCpJjlm9hlYNBQJ88,16566
13
+ pyrobale/objects/chat.py,sha256=w9_RyluyavgqLET5buArZWOPjKUNhj1RaINQyNhbY-A,16940
14
14
  pyrobale/objects/chatmember.py,sha256=IyAGmuZZ5HlJVYjrfXEKbLoNc7etMytrK-gOeKKo0CU,6895
15
15
  pyrobale/objects/chatphoto.py,sha256=vOb5xzpr3oBiCloi2_ufBnVlUfmcPqSTmMMMTTBYdJo,533
16
16
  pyrobale/objects/contact.py,sha256=6LDxT5RoGbY5Tsw64lg5-jvKSRmmvOiIJha1HqdTaG4,411
@@ -28,6 +28,7 @@ pyrobale/objects/labeledprice.py,sha256=d-fbOLzpkBslfor13BXGeVoySKCcSxsXY4QVwub2
28
28
  pyrobale/objects/location.py,sha256=w_9sRJRntLpNbn8Jk6JhRJVVigD9Bd4BxbjFyglxWhU,143
29
29
  pyrobale/objects/message.py,sha256=cCe0qU0ClGc66S7tW6TexnDzqyAafeKgN_h0h8UZMfs,14532
30
30
  pyrobale/objects/messageid.py,sha256=DrWKV8y9m9H8G_Fj68KgiJKwDJOGduNJGJ-Dyn8N580,95
31
+ pyrobale/objects/peerdata.py,sha256=-_uBrv1saKkwb_yyEf3FwpYsT5LLMHFcuETO8SCf_YA,815
31
32
  pyrobale/objects/photosize.py,sha256=I4hnmi46uoU-cW7hPN_tTT9kn0u80BtG5QJ3uRjoUiE,298
32
33
  pyrobale/objects/precheckoutquery.py,sha256=Rtjh1qqRc9TRZMJU1W5r0B8y7K5dayLMXX6WH9h1Ul4,470
33
34
  pyrobale/objects/replykeyboardmarkup.py,sha256=3dBiOs29q54tf281qKYcoO1Yjvn63WZfdkrbIoDUfck,1645
@@ -41,7 +42,7 @@ pyrobale/objects/video.py,sha256=DuZMGHio_w8yQvi87Vc3XpJOpEaltkM4_bNRSeocPZo,509
41
42
  pyrobale/objects/voice.py,sha256=ZdsJFH2IsBwelEk4rb4oZfX9xrfJ2_DgfjsMc0e4Tmg,148
42
43
  pyrobale/objects/webappdata.py,sha256=QlZlCa8Mylt8VmcdgdoHeyita5CVnz2WsT1yueEY1tY,78
43
44
  pyrobale/objects/webappinfo.py,sha256=qnTvfNqx91Yzbc1gO5y4XQ3w6g0RpMUqMuF5wk_EZMc,75
44
- pyrobale-0.3.8.dist-info/METADATA,sha256=386ZydRqEYd61G8-SgfJH_3eTz4YnNFgcb0l-nhp80A,5262
45
- pyrobale-0.3.8.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
46
- pyrobale-0.3.8.dist-info/licenses/LICENSE,sha256=rf_1ZkId-bcjw1kHBq6bV5t5TVob3RgjUyjfKr1CHAk,1070
47
- pyrobale-0.3.8.dist-info/RECORD,,
45
+ pyrobale-0.3.9.dist-info/METADATA,sha256=pjpHk7TtpgPg_hFCi7t7KOWG5oyvTiCyfqu4eCJZbyM,5290
46
+ pyrobale-0.3.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
47
+ pyrobale-0.3.9.dist-info/licenses/LICENSE,sha256=rf_1ZkId-bcjw1kHBq6bV5t5TVob3RgjUyjfKr1CHAk,1070
48
+ pyrobale-0.3.9.dist-info/RECORD,,