pyrobale 0.3.8.5__tar.gz → 0.3.9__tar.gz
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.
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/.github/workflows/docs.yml +1 -1
- pyrobale-0.3.9/.github/workflows/pypi.yml +36 -0
- pyrobale-0.3.9/.gitignore +1 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/PKG-INFO +3 -2
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyproject.toml +4 -4
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/client/__init__.py +109 -3
- pyrobale-0.3.9/pyrobale/objects/peerdata.py +25 -0
- pyrobale-0.3.9/version.py +2 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/.github/ISSUE_TEMPLATE/issue-template-/342/204/271/357/270/217.md" +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/LICENSE +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/README.md +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/examples/command.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/examples/echo_bot.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/examples/handler_system.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/examples/inline_keyboard.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/StateMachine/__init__.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/__init__.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/exceptions/__init__.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/exceptions/common.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/filters/__init__.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/filters/enum_filters.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/filters/func_filters.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/__init__.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/animation.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/audio.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/callbackquery.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/chat.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/chatmember.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/chatphoto.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/contact.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/copytextbutton.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/document.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/enums.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/file.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/inlinekeyboardbutton.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/inlinekeyboardmarkup.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/inputfile.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/inputmedias.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/invoice.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/keyboardbutton.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/labeledprice.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/location.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/message.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/messageid.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/photosize.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/precheckoutquery.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/replykeyboardmarkup.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/sticker.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/stickerset.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/successfulpayment.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/update.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/user.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/utils.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/video.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/voice.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/webappdata.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale/objects/webappinfo.py +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobale.png +0 -0
- {pyrobale-0.3.8.5 → pyrobale-0.3.9}/pyrobaletext.png +0 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
name: Publish to PyPI
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ main, master ]
|
6
|
+
|
7
|
+
jobs:
|
8
|
+
deploy:
|
9
|
+
runs-on: ubuntu-latest
|
10
|
+
|
11
|
+
steps:
|
12
|
+
- uses: actions/checkout@v4
|
13
|
+
|
14
|
+
- name: Set up Python
|
15
|
+
uses: actions/setup-python@v4
|
16
|
+
with:
|
17
|
+
python-version: '3.x'
|
18
|
+
|
19
|
+
- name: Extract version info
|
20
|
+
id: version
|
21
|
+
run: |
|
22
|
+
STABLE=$(python -c "from version import stable; print(str(stable).lower())")
|
23
|
+
VERSION=$(python -c "from version import version; print(version)")
|
24
|
+
echo "stable=$STABLE" >> $GITHUB_OUTPUT
|
25
|
+
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
26
|
+
echo "Stable: $STABLE, Version: $VERSION"
|
27
|
+
|
28
|
+
- name: Build and publish
|
29
|
+
if: steps.version.outputs.stable == 'true'
|
30
|
+
run: |
|
31
|
+
pip install build twine
|
32
|
+
python -m build
|
33
|
+
twine upload dist/* --username __token__ --password ${{ secrets.PYPI }}
|
34
|
+
env:
|
35
|
+
TWINE_USERNAME: __token__
|
36
|
+
TWINE_PASSWORD: ${{ secrets.PYPI }}
|
@@ -0,0 +1 @@
|
|
1
|
+
dist
|
@@ -1,10 +1,10 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: pyrobale
|
3
|
-
Version: 0.3.
|
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 <
|
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
|

|
@@ -1,9 +1,9 @@
|
|
1
1
|
[project]
|
2
2
|
name = "pyrobale"
|
3
|
-
version = "0.3.
|
3
|
+
version = "0.3.9"
|
4
4
|
authors = [
|
5
|
-
{ name = "Ali Safamanesh", email = "
|
6
|
-
{ name = "Aydin Rahbaran", email = "codewizaard9@gmail.com"}
|
5
|
+
{ name = "Ali Safamanesh", email = "daradege@proton.me" },
|
6
|
+
{ name = "Aydin Rahbaran", email = "codewizaard9@gmail.com"}
|
7
7
|
]
|
8
8
|
description = "A python wrapper for bale api"
|
9
9
|
readme = "README.md"
|
@@ -14,7 +14,7 @@ classifiers = [
|
|
14
14
|
"Operating System :: OS Independent",
|
15
15
|
]
|
16
16
|
license = { file = "LICENSE" }
|
17
|
-
dependencies = ["aiohttp"]
|
17
|
+
dependencies = ["aiohttp", "beautifulsoup4"]
|
18
18
|
[project.urls]
|
19
19
|
github = "https://github.com/pyrobale/pyrobale"
|
20
20
|
website = "https://pyrobale.github.io"
|
@@ -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,
|
@@ -725,7 +731,100 @@ class Client:
|
|
725
731
|
self.requests_base + "/getChat", data={"chat_id": chat_id}
|
726
732
|
)
|
727
733
|
return Chat(**pythonize(data["result"]))
|
728
|
-
|
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("‌", "")
|
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
|
+
|
729
828
|
async def get_chat_members_count(self, chat_id: int) -> int:
|
730
829
|
"""Get the number of members in a chat.
|
731
830
|
|
@@ -941,6 +1040,11 @@ class Client:
|
|
941
1040
|
if update_id:
|
942
1041
|
self.last_update_id = update_id + 1
|
943
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
|
+
|
944
1048
|
for waiter in list(self._waiters):
|
945
1049
|
w_type, check, future = waiter
|
946
1050
|
if w_type.value in update:
|
@@ -956,6 +1060,8 @@ class Client:
|
|
956
1060
|
update_type = handler["type"].value
|
957
1061
|
if update_type in update:
|
958
1062
|
raw_event = update[update_type]
|
1063
|
+
|
1064
|
+
|
959
1065
|
event = self._convert_event(handler["type"], raw_event)
|
960
1066
|
|
961
1067
|
if handler["type"] == UpdatesTypes.COMMAND:
|
@@ -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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|