botbaleirp 0.0.1__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.
- botbaleirp-0.0.1/PKG-INFO +11 -0
- botbaleirp-0.0.1/botbaleirp/__init__.py +7 -0
- botbaleirp-0.0.1/botbaleirp/bale_types.py +215 -0
- botbaleirp-0.0.1/botbaleirp/bot.py +340 -0
- botbaleirp-0.0.1/botbaleirp/errors.py +11 -0
- botbaleirp-0.0.1/botbaleirp/utils.py +26 -0
- botbaleirp-0.0.1/botbaleirp.egg-info/PKG-INFO +11 -0
- botbaleirp-0.0.1/botbaleirp.egg-info/SOURCES.txt +11 -0
- botbaleirp-0.0.1/botbaleirp.egg-info/dependency_links.txt +1 -0
- botbaleirp-0.0.1/botbaleirp.egg-info/requires.txt +1 -0
- botbaleirp-0.0.1/botbaleirp.egg-info/top_level.txt +1 -0
- botbaleirp-0.0.1/setup.cfg +4 -0
- botbaleirp-0.0.1/setup.py +11 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: botbaleirp
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: کتابخانه کامل پایتون برای API بازوی بله
|
|
5
|
+
Author: Mohammad Latifi
|
|
6
|
+
Requires-Python: >=3.7
|
|
7
|
+
Requires-Dist: requests>=2.25.0
|
|
8
|
+
Dynamic: author
|
|
9
|
+
Dynamic: requires-dist
|
|
10
|
+
Dynamic: requires-python
|
|
11
|
+
Dynamic: summary
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import List, Optional, Dict, Any
|
|
3
|
+
|
|
4
|
+
@dataclass
|
|
5
|
+
class User:
|
|
6
|
+
id: int
|
|
7
|
+
is_bot: bool
|
|
8
|
+
first_name: str
|
|
9
|
+
last_name: Optional[str] = None
|
|
10
|
+
username: Optional[str] = None
|
|
11
|
+
language_code: Optional[str] = None
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class Chat:
|
|
15
|
+
id: int
|
|
16
|
+
type: str
|
|
17
|
+
title: Optional[str] = None
|
|
18
|
+
username: Optional[str] = None
|
|
19
|
+
first_name: Optional[str] = None
|
|
20
|
+
last_name: Optional[str] = None
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class MessageEntity:
|
|
24
|
+
type: str
|
|
25
|
+
offset: int
|
|
26
|
+
length: int
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class PhotoSize:
|
|
30
|
+
file_id: str
|
|
31
|
+
file_unique_id: str
|
|
32
|
+
width: int
|
|
33
|
+
height: int
|
|
34
|
+
file_size: Optional[int] = None
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class Document:
|
|
38
|
+
file_id: str
|
|
39
|
+
file_unique_id: str
|
|
40
|
+
thumbnail: Optional[PhotoSize] = None
|
|
41
|
+
file_name: Optional[str] = None
|
|
42
|
+
mime_type: Optional[str] = None
|
|
43
|
+
file_size: Optional[int] = None
|
|
44
|
+
|
|
45
|
+
@dataclass
|
|
46
|
+
class Audio:
|
|
47
|
+
file_id: str
|
|
48
|
+
file_unique_id: str
|
|
49
|
+
duration: int
|
|
50
|
+
title: Optional[str] = None
|
|
51
|
+
file_name: Optional[str] = None
|
|
52
|
+
mime_type: Optional[str] = None
|
|
53
|
+
file_size: Optional[int] = None
|
|
54
|
+
|
|
55
|
+
@dataclass
|
|
56
|
+
class Video:
|
|
57
|
+
file_id: str
|
|
58
|
+
file_unique_id: str
|
|
59
|
+
width: int
|
|
60
|
+
height: int
|
|
61
|
+
duration: int
|
|
62
|
+
file_name: Optional[str] = None
|
|
63
|
+
mime_type: Optional[str] = None
|
|
64
|
+
file_size: Optional[int] = None
|
|
65
|
+
|
|
66
|
+
@dataclass
|
|
67
|
+
class Voice:
|
|
68
|
+
file_id: str
|
|
69
|
+
file_unique_id: str
|
|
70
|
+
duration: int
|
|
71
|
+
mime_type: Optional[str] = None
|
|
72
|
+
file_size: Optional[int] = None
|
|
73
|
+
|
|
74
|
+
@dataclass
|
|
75
|
+
class Animation:
|
|
76
|
+
file_id: str
|
|
77
|
+
file_unique_id: str
|
|
78
|
+
width: int
|
|
79
|
+
height: int
|
|
80
|
+
duration: int
|
|
81
|
+
thumbnail: Optional[PhotoSize] = None
|
|
82
|
+
file_name: Optional[str] = None
|
|
83
|
+
mime_type: Optional[str] = None
|
|
84
|
+
file_size: Optional[int] = None
|
|
85
|
+
|
|
86
|
+
@dataclass
|
|
87
|
+
class Contact:
|
|
88
|
+
phone_number: str
|
|
89
|
+
first_name: str
|
|
90
|
+
last_name: Optional[str] = None
|
|
91
|
+
user_id: Optional[int] = None
|
|
92
|
+
|
|
93
|
+
@dataclass
|
|
94
|
+
class Location:
|
|
95
|
+
longitude: float
|
|
96
|
+
latitude: float
|
|
97
|
+
|
|
98
|
+
@dataclass
|
|
99
|
+
class Invoice:
|
|
100
|
+
title: str
|
|
101
|
+
description: str
|
|
102
|
+
total_amount: int
|
|
103
|
+
|
|
104
|
+
@dataclass
|
|
105
|
+
class SuccessfulPayment:
|
|
106
|
+
currency: str
|
|
107
|
+
total_amount: int
|
|
108
|
+
invoice_payload: str
|
|
109
|
+
telegram_payment_charge_id: str
|
|
110
|
+
provider_payment_charge_id: str
|
|
111
|
+
|
|
112
|
+
@dataclass
|
|
113
|
+
class PreCheckoutQuery:
|
|
114
|
+
id: str
|
|
115
|
+
from_user: User
|
|
116
|
+
currency: str
|
|
117
|
+
total_amount: int
|
|
118
|
+
invoice_payload: str
|
|
119
|
+
|
|
120
|
+
@classmethod
|
|
121
|
+
def from_dict(cls, data):
|
|
122
|
+
data['from_user'] = User(**data.pop('from'))
|
|
123
|
+
return cls(**data)
|
|
124
|
+
|
|
125
|
+
@dataclass
|
|
126
|
+
class CallbackQuery:
|
|
127
|
+
id: str
|
|
128
|
+
from_user: User
|
|
129
|
+
message: Optional['Message'] = None
|
|
130
|
+
data: Optional[str] = None
|
|
131
|
+
|
|
132
|
+
@classmethod
|
|
133
|
+
def from_dict(cls, data):
|
|
134
|
+
data['from_user'] = User(**data.pop('from'))
|
|
135
|
+
if data.get('message'):
|
|
136
|
+
data['message'] = Message.from_dict(data['message'])
|
|
137
|
+
return cls(**data)
|
|
138
|
+
|
|
139
|
+
@dataclass
|
|
140
|
+
class Message:
|
|
141
|
+
message_id: int
|
|
142
|
+
date: int
|
|
143
|
+
chat: Chat
|
|
144
|
+
from_user: Optional[User] = None
|
|
145
|
+
text: Optional[str] = None
|
|
146
|
+
caption: Optional[str] = None
|
|
147
|
+
photo: Optional[List[PhotoSize]] = None
|
|
148
|
+
video: Optional[Video] = None
|
|
149
|
+
audio: Optional[Audio] = None
|
|
150
|
+
voice: Optional[Voice] = None
|
|
151
|
+
document: Optional[Document] = None
|
|
152
|
+
animation: Optional[Animation] = None
|
|
153
|
+
contact: Optional[Contact] = None
|
|
154
|
+
location: Optional[Location] = None
|
|
155
|
+
reply_to_message: Optional['Message'] = None
|
|
156
|
+
entities: Optional[List[MessageEntity]] = None
|
|
157
|
+
new_chat_members: Optional[List[User]] = None
|
|
158
|
+
left_chat_member: Optional[User] = None
|
|
159
|
+
invoice: Optional[Invoice] = None
|
|
160
|
+
successful_payment: Optional[SuccessfulPayment] = None
|
|
161
|
+
|
|
162
|
+
@classmethod
|
|
163
|
+
def from_dict(cls, data):
|
|
164
|
+
if data.get('from'):
|
|
165
|
+
data['from_user'] = User(**data.pop('from'))
|
|
166
|
+
if data.get('chat'):
|
|
167
|
+
data['chat'] = Chat(**data['chat'])
|
|
168
|
+
if data.get('reply_to_message'):
|
|
169
|
+
data['reply_to_message'] = cls.from_dict(data['reply_to_message'])
|
|
170
|
+
return cls(**{k: v for k, v in data.items() if k in cls.__annotations__})
|
|
171
|
+
|
|
172
|
+
@dataclass
|
|
173
|
+
class Update:
|
|
174
|
+
update_id: int
|
|
175
|
+
message: Optional[Message] = None
|
|
176
|
+
edited_message: Optional[Message] = None
|
|
177
|
+
callback_query: Optional[CallbackQuery] = None
|
|
178
|
+
pre_checkout_query: Optional[PreCheckoutQuery] = None
|
|
179
|
+
|
|
180
|
+
@classmethod
|
|
181
|
+
def from_dict(cls, data):
|
|
182
|
+
if data.get('message'):
|
|
183
|
+
data['message'] = Message.from_dict(data['message'])
|
|
184
|
+
if data.get('callback_query'):
|
|
185
|
+
data['callback_query'] = CallbackQuery.from_dict(data['callback_query'])
|
|
186
|
+
if data.get('pre_checkout_query'):
|
|
187
|
+
data['pre_checkout_query'] = PreCheckoutQuery.from_dict(data['pre_checkout_query'])
|
|
188
|
+
return cls(**data)
|
|
189
|
+
|
|
190
|
+
@dataclass
|
|
191
|
+
class File:
|
|
192
|
+
file_id: str
|
|
193
|
+
file_unique_id: str
|
|
194
|
+
file_size: Optional[int] = None
|
|
195
|
+
file_path: Optional[str] = None
|
|
196
|
+
|
|
197
|
+
@dataclass
|
|
198
|
+
class ChatMember:
|
|
199
|
+
status: str
|
|
200
|
+
user: User
|
|
201
|
+
|
|
202
|
+
@classmethod
|
|
203
|
+
def from_dict(cls, data):
|
|
204
|
+
data['user'] = User(**data['user'])
|
|
205
|
+
return cls(**data)
|
|
206
|
+
|
|
207
|
+
@dataclass
|
|
208
|
+
class ChatFullInfo(Chat):
|
|
209
|
+
bio: Optional[str] = None
|
|
210
|
+
description: Optional[str] = None
|
|
211
|
+
invite_link: Optional[str] = None
|
|
212
|
+
|
|
213
|
+
@dataclass
|
|
214
|
+
class MessageId:
|
|
215
|
+
message_id: int
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import time
|
|
3
|
+
from typing import Dict, Any, Optional, List, Union, BinaryIO, Callable
|
|
4
|
+
import requests
|
|
5
|
+
from . import bale_types as types
|
|
6
|
+
from .errors import BaleAPIError, BaleNetworkError
|
|
7
|
+
from .utils import prepare_upload_file
|
|
8
|
+
|
|
9
|
+
class Bot:
|
|
10
|
+
BASE_URL = "https://tapi.bale.ai/bot{}"
|
|
11
|
+
|
|
12
|
+
def __init__(self, token: str):
|
|
13
|
+
self.token = token
|
|
14
|
+
self.session = requests.Session()
|
|
15
|
+
self._offset = None
|
|
16
|
+
|
|
17
|
+
def _request(self, method: str, params: Dict = None, files: Dict = None) -> Any:
|
|
18
|
+
url = self.BASE_URL.format(self.token) + f"/{method}"
|
|
19
|
+
try:
|
|
20
|
+
if files:
|
|
21
|
+
resp = self.session.post(url, data=params, files=files)
|
|
22
|
+
elif method in ('getMe', 'getUpdates', 'getWebhookInfo', 'deleteWebhook'):
|
|
23
|
+
resp = self.session.get(url, params=params)
|
|
24
|
+
else:
|
|
25
|
+
resp = self.session.post(url, json=params)
|
|
26
|
+
resp.raise_for_status()
|
|
27
|
+
data = resp.json()
|
|
28
|
+
if not data.get('ok'):
|
|
29
|
+
raise BaleAPIError(data.get('description', 'Unknown error'),
|
|
30
|
+
data.get('error_code'), data.get('parameters'))
|
|
31
|
+
return data.get('result')
|
|
32
|
+
except requests.exceptions.RequestException as e:
|
|
33
|
+
raise BaleNetworkError(str(e))
|
|
34
|
+
|
|
35
|
+
# ----------------------- دریافت آپدیت -----------------------
|
|
36
|
+
def get_updates(self, offset: Optional[int] = None, limit: int = 100, timeout: int = 0) -> List[types.Update]:
|
|
37
|
+
if offset is None and self._offset is not None:
|
|
38
|
+
offset = self._offset
|
|
39
|
+
params = {'limit': limit, 'timeout': timeout}
|
|
40
|
+
if offset:
|
|
41
|
+
params['offset'] = offset
|
|
42
|
+
result = self._request('getUpdates', params)
|
|
43
|
+
updates = [types.Update.from_dict(u) for u in result]
|
|
44
|
+
if updates:
|
|
45
|
+
self._offset = updates[-1].update_id + 1
|
|
46
|
+
return updates
|
|
47
|
+
|
|
48
|
+
def start_polling(self, callback: Callable[[types.Update], None], interval: float = 0.5):
|
|
49
|
+
self._offset = None
|
|
50
|
+
while True:
|
|
51
|
+
try:
|
|
52
|
+
for update in self.get_updates():
|
|
53
|
+
callback(update)
|
|
54
|
+
except KeyboardInterrupt:
|
|
55
|
+
break
|
|
56
|
+
except Exception as e:
|
|
57
|
+
print(f"Polling error: {e}")
|
|
58
|
+
time.sleep(interval)
|
|
59
|
+
time.sleep(interval)
|
|
60
|
+
|
|
61
|
+
def set_webhook(self, url: str) -> bool:
|
|
62
|
+
return self._request('setWebhook', {'url': url}) is True
|
|
63
|
+
|
|
64
|
+
def delete_webhook(self) -> bool:
|
|
65
|
+
return self._request('deleteWebhook') is True
|
|
66
|
+
|
|
67
|
+
def get_webhook_info(self) -> Dict:
|
|
68
|
+
return self._request('getWebhookInfo')
|
|
69
|
+
|
|
70
|
+
# ----------------------- اطلاعات بازو -----------------------
|
|
71
|
+
def get_me(self) -> types.User:
|
|
72
|
+
return types.User(**self._request('getMe'))
|
|
73
|
+
|
|
74
|
+
# ----------------------- ارسال پیام -----------------------
|
|
75
|
+
def send_message(self, chat_id: Union[int, str], text: str,
|
|
76
|
+
reply_to_message_id: int = None, reply_markup: Dict = None) -> types.Message:
|
|
77
|
+
params = {'chat_id': chat_id, 'text': text}
|
|
78
|
+
if reply_to_message_id: params['reply_to_message_id'] = reply_to_message_id
|
|
79
|
+
if reply_markup: params['reply_markup'] = reply_markup
|
|
80
|
+
return types.Message.from_dict(self._request('sendMessage', params))
|
|
81
|
+
|
|
82
|
+
def forward_message(self, chat_id: Union[int, str], from_chat_id: Union[int, str],
|
|
83
|
+
message_id: int) -> types.Message:
|
|
84
|
+
params = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id}
|
|
85
|
+
return types.Message.from_dict(self._request('forwardMessage', params))
|
|
86
|
+
|
|
87
|
+
def copy_message(self, chat_id: Union[int, str], from_chat_id: Union[int, str],
|
|
88
|
+
message_id: int) -> types.MessageId:
|
|
89
|
+
params = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id}
|
|
90
|
+
return types.MessageId(**self._request('copyMessage', params))
|
|
91
|
+
|
|
92
|
+
def send_photo(self, chat_id: Union[int, str], photo: Union[str, bytes, BinaryIO],
|
|
93
|
+
caption: str = None, reply_to_message_id: int = None,
|
|
94
|
+
reply_markup: Dict = None) -> types.Message:
|
|
95
|
+
name, data = prepare_upload_file(photo)
|
|
96
|
+
params = {'chat_id': chat_id, 'caption': caption,
|
|
97
|
+
'reply_to_message_id': reply_to_message_id, 'reply_markup': reply_markup}
|
|
98
|
+
files = None
|
|
99
|
+
if name and data:
|
|
100
|
+
files = {'photo': (name, data)}
|
|
101
|
+
else:
|
|
102
|
+
params['photo'] = data
|
|
103
|
+
return types.Message.from_dict(self._request('sendPhoto', params, files))
|
|
104
|
+
|
|
105
|
+
def send_audio(self, chat_id: Union[int, str], audio: Union[str, bytes, BinaryIO],
|
|
106
|
+
caption: str = None, reply_to_message_id: int = None,
|
|
107
|
+
reply_markup: Dict = None) -> types.Message:
|
|
108
|
+
name, data = prepare_upload_file(audio)
|
|
109
|
+
params = {'chat_id': chat_id, 'caption': caption,
|
|
110
|
+
'reply_to_message_id': reply_to_message_id, 'reply_markup': reply_markup}
|
|
111
|
+
files = None
|
|
112
|
+
if name and data:
|
|
113
|
+
files = {'audio': (name, data)}
|
|
114
|
+
else:
|
|
115
|
+
params['audio'] = data
|
|
116
|
+
return types.Message.from_dict(self._request('sendAudio', params, files))
|
|
117
|
+
|
|
118
|
+
def send_document(self, chat_id: Union[int, str], document: Union[str, bytes, BinaryIO],
|
|
119
|
+
caption: str = None, reply_to_message_id: int = None,
|
|
120
|
+
reply_markup: Dict = None) -> types.Message:
|
|
121
|
+
name, data = prepare_upload_file(document)
|
|
122
|
+
params = {'chat_id': chat_id, 'caption': caption,
|
|
123
|
+
'reply_to_message_id': reply_to_message_id, 'reply_markup': reply_markup}
|
|
124
|
+
files = None
|
|
125
|
+
if name and data:
|
|
126
|
+
files = {'document': (name, data)}
|
|
127
|
+
else:
|
|
128
|
+
params['document'] = data
|
|
129
|
+
return types.Message.from_dict(self._request('sendDocument', params, files))
|
|
130
|
+
|
|
131
|
+
def send_video(self, chat_id: Union[int, str], video: Union[str, bytes, BinaryIO],
|
|
132
|
+
caption: str = None, reply_to_message_id: int = None,
|
|
133
|
+
reply_markup: Dict = None) -> types.Message:
|
|
134
|
+
name, data = prepare_upload_file(video)
|
|
135
|
+
params = {'chat_id': chat_id, 'caption': caption,
|
|
136
|
+
'reply_to_message_id': reply_to_message_id, 'reply_markup': reply_markup}
|
|
137
|
+
files = None
|
|
138
|
+
if name and data:
|
|
139
|
+
files = {'video': (name, data)}
|
|
140
|
+
else:
|
|
141
|
+
params['video'] = data
|
|
142
|
+
return types.Message.from_dict(self._request('sendVideo', params, files))
|
|
143
|
+
|
|
144
|
+
def send_animation(self, chat_id: Union[int, str], animation: Union[str, bytes, BinaryIO],
|
|
145
|
+
reply_to_message_id: int = None, reply_markup: Dict = None) -> types.Message:
|
|
146
|
+
name, data = prepare_upload_file(animation)
|
|
147
|
+
params = {'chat_id': chat_id, 'reply_to_message_id': reply_to_message_id, 'reply_markup': reply_markup}
|
|
148
|
+
files = None
|
|
149
|
+
if name and data:
|
|
150
|
+
files = {'animation': (name, data)}
|
|
151
|
+
else:
|
|
152
|
+
params['animation'] = data
|
|
153
|
+
return types.Message.from_dict(self._request('sendAnimation', params, files))
|
|
154
|
+
|
|
155
|
+
def send_voice(self, chat_id: Union[int, str], voice: Union[str, bytes, BinaryIO],
|
|
156
|
+
caption: str = None, reply_to_message_id: int = None,
|
|
157
|
+
reply_markup: Dict = None) -> types.Message:
|
|
158
|
+
name, data = prepare_upload_file(voice)
|
|
159
|
+
params = {'chat_id': chat_id, 'caption': caption,
|
|
160
|
+
'reply_to_message_id': reply_to_message_id, 'reply_markup': reply_markup}
|
|
161
|
+
files = None
|
|
162
|
+
if name and data:
|
|
163
|
+
files = {'voice': (name, data)}
|
|
164
|
+
else:
|
|
165
|
+
params['voice'] = data
|
|
166
|
+
return types.Message.from_dict(self._request('sendVoice', params, files))
|
|
167
|
+
|
|
168
|
+
def send_media_group(self, chat_id: Union[int, str], media: List[Dict],
|
|
169
|
+
reply_to_message_id: int = None) -> List[types.Message]:
|
|
170
|
+
params = {'chat_id': chat_id, 'media': json.dumps(media), 'reply_to_message_id': reply_to_message_id}
|
|
171
|
+
result = self._request('sendMediaGroup', params)
|
|
172
|
+
return [types.Message.from_dict(msg) for msg in result]
|
|
173
|
+
|
|
174
|
+
def send_location(self, chat_id: Union[int, str], latitude: float, longitude: float,
|
|
175
|
+
horizontal_accuracy: float = None, reply_to_message_id: int = None,
|
|
176
|
+
reply_markup: Dict = None) -> types.Message:
|
|
177
|
+
params = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude,
|
|
178
|
+
'horizontal_accuracy': horizontal_accuracy, 'reply_to_message_id': reply_to_message_id,
|
|
179
|
+
'reply_markup': reply_markup}
|
|
180
|
+
return types.Message.from_dict(self._request('sendLocation', {k: v for k, v in params.items() if v}))
|
|
181
|
+
|
|
182
|
+
def send_contact(self, chat_id: Union[int, str], phone_number: str, first_name: str,
|
|
183
|
+
last_name: str = None, reply_to_message_id: int = None,
|
|
184
|
+
reply_markup: Dict = None) -> types.Message:
|
|
185
|
+
params = {'chat_id': chat_id, 'phone_number': phone_number, 'first_name': first_name,
|
|
186
|
+
'last_name': last_name, 'reply_to_message_id': reply_to_message_id, 'reply_markup': reply_markup}
|
|
187
|
+
return types.Message.from_dict(self._request('sendContact', {k: v for k, v in params.items() if v}))
|
|
188
|
+
|
|
189
|
+
def send_chat_action(self, chat_id: Union[int, str], action: str) -> bool:
|
|
190
|
+
return self._request('sendChatAction', {'chat_id': chat_id, 'action': action}) is True
|
|
191
|
+
|
|
192
|
+
# ----------------------- فایل -----------------------
|
|
193
|
+
def get_file(self, file_id: str) -> types.File:
|
|
194
|
+
return types.File(**self._request('getFile', {'file_id': file_id}))
|
|
195
|
+
|
|
196
|
+
def download_file(self, file_path: str, destination: str = None) -> Optional[bytes]:
|
|
197
|
+
url = f"https://tapi.bale.ai/file/bot{self.token}/{file_path}"
|
|
198
|
+
resp = self.session.get(url)
|
|
199
|
+
resp.raise_for_status()
|
|
200
|
+
if destination:
|
|
201
|
+
with open(destination, 'wb') as f:
|
|
202
|
+
f.write(resp.content)
|
|
203
|
+
return None
|
|
204
|
+
return resp.content
|
|
205
|
+
|
|
206
|
+
# ----------------------- پاسخ به callback -----------------------
|
|
207
|
+
def answer_callback_query(self, callback_query_id: str, text: str = None, show_alert: bool = False) -> bool:
|
|
208
|
+
params = {'callback_query_id': callback_query_id, 'text': text, 'show_alert': show_alert}
|
|
209
|
+
return self._request('answerCallbackQuery', {k: v for k, v in params.items() if v}) is True
|
|
210
|
+
|
|
211
|
+
def ask_review(self, user_id: int, delay_seconds: int = 0) -> bool:
|
|
212
|
+
return self._request('askReview', {'user_id': user_id, 'delay_seconds': delay_seconds}) is True
|
|
213
|
+
|
|
214
|
+
# ----------------------- مدیریت گروه -----------------------
|
|
215
|
+
def ban_chat_member(self, chat_id: Union[int, str], user_id: int) -> bool:
|
|
216
|
+
return self._request('banChatMember', {'chat_id': chat_id, 'user_id': user_id}) is True
|
|
217
|
+
|
|
218
|
+
def unban_chat_member(self, chat_id: Union[int, str], user_id: int, only_if_banned: bool = True) -> bool:
|
|
219
|
+
return self._request('unbanChatMember', {'chat_id': chat_id, 'user_id': user_id, 'only_if_banned': only_if_banned}) is True
|
|
220
|
+
|
|
221
|
+
def promote_chat_member(self, chat_id: Union[int, str], user_id: int,
|
|
222
|
+
can_change_info=False, can_post_messages=False, can_edit_messages=False,
|
|
223
|
+
can_delete_messages=False, can_manage_video_chats=False,
|
|
224
|
+
can_invite_users=False, can_restrict_members=False) -> bool:
|
|
225
|
+
params = {'chat_id': chat_id, 'user_id': user_id, 'can_change_info': can_change_info,
|
|
226
|
+
'can_post_messages': can_post_messages, 'can_edit_messages': can_edit_messages,
|
|
227
|
+
'can_delete_messages': can_delete_messages, 'can_manage_video_chats': can_manage_video_chats,
|
|
228
|
+
'can_invite_users': can_invite_users, 'can_restrict_members': can_restrict_members}
|
|
229
|
+
return self._request('promoteChatMember', {k: v for k, v in params.items() if v}) is True
|
|
230
|
+
|
|
231
|
+
def set_chat_photo(self, chat_id: Union[int, str], photo: Union[str, bytes, BinaryIO]) -> bool:
|
|
232
|
+
name, data = prepare_upload_file(photo)
|
|
233
|
+
if not name or not isinstance(data, (bytes, BinaryIO)):
|
|
234
|
+
raise ValueError("فقط آپلود فایل محلی پشتیبانی میشود")
|
|
235
|
+
return self._request('setChatPhoto', {'chat_id': chat_id}, files={'photo': (name, data)}) is True
|
|
236
|
+
|
|
237
|
+
def delete_chat_photo(self, chat_id: Union[int, str]) -> bool:
|
|
238
|
+
return self._request('deleteChatPhoto', {'chat_id': chat_id}) is True
|
|
239
|
+
|
|
240
|
+
def leave_chat(self, chat_id: Union[int, str]) -> bool:
|
|
241
|
+
return self._request('leaveChat', {'chat_id': chat_id}) is True
|
|
242
|
+
|
|
243
|
+
def get_chat(self, chat_id: Union[int, str]) -> types.ChatFullInfo:
|
|
244
|
+
return types.ChatFullInfo(**self._request('getChat', {'chat_id': chat_id}))
|
|
245
|
+
|
|
246
|
+
def get_chat_administrators(self, chat_id: Union[int, str]) -> List[types.ChatMember]:
|
|
247
|
+
result = self._request('getChatAdministrators', {'chat_id': chat_id})
|
|
248
|
+
return [types.ChatMember.from_dict(admin) for admin in result]
|
|
249
|
+
|
|
250
|
+
def get_chat_members_count(self, chat_id: Union[int, str]) -> int:
|
|
251
|
+
return self._request('getChatMembersCount', {'chat_id': chat_id})
|
|
252
|
+
|
|
253
|
+
def get_chat_member(self, chat_id: Union[int, str], user_id: int) -> types.ChatMember:
|
|
254
|
+
return types.ChatMember.from_dict(self._request('getChatMember', {'chat_id': chat_id, 'user_id': user_id}))
|
|
255
|
+
|
|
256
|
+
def pin_chat_message(self, chat_id: Union[int, str], message_id: int) -> bool:
|
|
257
|
+
return self._request('pinChatMessage', {'chat_id': chat_id, 'message_id': message_id}) is True
|
|
258
|
+
|
|
259
|
+
def unpin_chat_message(self, chat_id: Union[int, str], message_id: int) -> bool:
|
|
260
|
+
return self._request('unpinChatMessage', {'chat_id': chat_id, 'message_id': message_id}) is True
|
|
261
|
+
|
|
262
|
+
def unpin_all_chat_messages(self, chat_id: Union[int, str]) -> bool:
|
|
263
|
+
return self._request('unpinAllChatMessages', {'chat_id': chat_id}) is True
|
|
264
|
+
|
|
265
|
+
def set_chat_title(self, chat_id: Union[int, str], title: str) -> bool:
|
|
266
|
+
return self._request('setChatTitle', {'chat_id': chat_id, 'title': title}) is True
|
|
267
|
+
|
|
268
|
+
def set_chat_description(self, chat_id: Union[int, str], description: str) -> bool:
|
|
269
|
+
return self._request('setChatDescription', {'chat_id': chat_id, 'description': description}) is True
|
|
270
|
+
|
|
271
|
+
def create_chat_invite_link(self, chat_id: Union[int, str]) -> str:
|
|
272
|
+
return self._request('createChatInviteLink', {'chat_id': chat_id})
|
|
273
|
+
|
|
274
|
+
def revoke_chat_invite_link(self, chat_id: Union[int, str], invite_link: str) -> str:
|
|
275
|
+
return self._request('revokeChatInviteLink', {'chat_id': chat_id, 'invite_link': invite_link})
|
|
276
|
+
|
|
277
|
+
def export_chat_invite_link(self, chat_id: Union[int, str]) -> str:
|
|
278
|
+
return self._request('exportChatInviteLink', {'chat_id': chat_id})
|
|
279
|
+
|
|
280
|
+
# ----------------------- ویرایش پیام -----------------------
|
|
281
|
+
def edit_message_text(self, chat_id: Union[int, str], message_id: int, text: str,
|
|
282
|
+
reply_markup: Dict = None) -> types.Message:
|
|
283
|
+
params = {'chat_id': chat_id, 'message_id': message_id, 'text': text, 'reply_markup': reply_markup}
|
|
284
|
+
return types.Message.from_dict(self._request('editMessageText', {k: v for k, v in params.items() if v}))
|
|
285
|
+
|
|
286
|
+
def edit_message_caption(self, chat_id: Union[int, str], message_id: int, caption: str,
|
|
287
|
+
reply_markup: Dict = None) -> types.Message:
|
|
288
|
+
params = {'chat_id': chat_id, 'message_id': message_id, 'caption': caption, 'reply_markup': reply_markup}
|
|
289
|
+
return types.Message.from_dict(self._request('editMessageCaption', {k: v for k, v in params.items() if v}))
|
|
290
|
+
|
|
291
|
+
def edit_message_reply_markup(self, chat_id: Union[int, str], message_id: int,
|
|
292
|
+
reply_markup: Dict) -> types.Message:
|
|
293
|
+
params = {'chat_id': chat_id, 'message_id': message_id, 'reply_markup': reply_markup}
|
|
294
|
+
return types.Message.from_dict(self._request('editMessageReplyMarkup', params))
|
|
295
|
+
|
|
296
|
+
def delete_message(self, chat_id: Union[int, str], message_id: int) -> bool:
|
|
297
|
+
return self._request('deleteMessage', {'chat_id': chat_id, 'message_id': message_id}) is True
|
|
298
|
+
|
|
299
|
+
# ----------------------- پرداخت -----------------------
|
|
300
|
+
def send_invoice(self, chat_id: Union[int, str], title: str, description: str,
|
|
301
|
+
payload: str, provider_token: str, prices: List[Dict],
|
|
302
|
+
photo_url: str = None, reply_to_message_id: int = None) -> types.Message:
|
|
303
|
+
params = {'chat_id': chat_id, 'title': title, 'description': description, 'payload': payload,
|
|
304
|
+
'provider_token': provider_token, 'prices': json.dumps(prices), 'photo_url': photo_url,
|
|
305
|
+
'reply_to_message_id': reply_to_message_id}
|
|
306
|
+
return types.Message.from_dict(self._request('sendInvoice', {k: v for k, v in params.items() if v}))
|
|
307
|
+
|
|
308
|
+
def create_invoice_link(self, title: str, description: str, payload: str,
|
|
309
|
+
provider_token: str, prices: List[Dict]) -> str:
|
|
310
|
+
params = {'title': title, 'description': description, 'payload': payload,
|
|
311
|
+
'provider_token': provider_token, 'prices': json.dumps(prices)}
|
|
312
|
+
return self._request('createInvoiceLink', params)
|
|
313
|
+
|
|
314
|
+
def answer_pre_checkout_query(self, pre_checkout_query_id: str, ok: bool,
|
|
315
|
+
error_message: str = None) -> bool:
|
|
316
|
+
params = {'pre_checkout_query_id': pre_checkout_query_id, 'ok': ok, 'error_message': error_message}
|
|
317
|
+
return self._request('answerPreCheckoutQuery', {k: v for k, v in params.items() if v}) is True
|
|
318
|
+
|
|
319
|
+
def inquire_transaction(self, transaction_id: str) -> Dict:
|
|
320
|
+
return self._request('inquireTransaction', {'transaction_id': transaction_id})
|
|
321
|
+
|
|
322
|
+
# ----------------------- استیکر -----------------------
|
|
323
|
+
def upload_sticker_file(self, user_id: int, sticker: Union[str, bytes, BinaryIO]) -> types.File:
|
|
324
|
+
name, data = prepare_upload_file(sticker)
|
|
325
|
+
params = {'user_id': user_id}
|
|
326
|
+
files = None
|
|
327
|
+
if name and data:
|
|
328
|
+
files = {'sticker': (name, data)}
|
|
329
|
+
else:
|
|
330
|
+
params['sticker'] = data
|
|
331
|
+
return types.File(**self._request('uploadStickerFile', params, files))
|
|
332
|
+
|
|
333
|
+
def create_new_sticker_set(self, user_id: int, name: str, title: str,
|
|
334
|
+
stickers: List[Dict]) -> bool:
|
|
335
|
+
params = {'user_id': user_id, 'name': name, 'title': title, 'stickers': json.dumps(stickers)}
|
|
336
|
+
return self._request('createNewStickerSet', params) is True
|
|
337
|
+
|
|
338
|
+
def add_sticker_to_set(self, user_id: int, name: str, sticker: Dict) -> bool:
|
|
339
|
+
params = {'user_id': user_id, 'name': name, 'sticker': json.dumps(sticker)}
|
|
340
|
+
return self._request('addStickerToSet', params) is True
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class BaleError(Exception):
|
|
2
|
+
def __init__(self, message, error_code=None, parameters=None):
|
|
3
|
+
super().__init__(message)
|
|
4
|
+
self.error_code = error_code
|
|
5
|
+
self.parameters = parameters
|
|
6
|
+
|
|
7
|
+
class BaleAPIError(BaleError):
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
class BaleNetworkError(BaleError):
|
|
11
|
+
pass
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import List, Dict, Union, Any
|
|
3
|
+
|
|
4
|
+
def make_reply_keyboard(buttons: List[List[str]], resize_keyboard=True, one_time_keyboard=False):
|
|
5
|
+
return {
|
|
6
|
+
"keyboard": [[{"text": btn} for btn in row] for row in buttons],
|
|
7
|
+
"resize_keyboard": resize_keyboard,
|
|
8
|
+
"one_time_keyboard": one_time_keyboard
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
def make_inline_keyboard(buttons: List[List[Dict[str, str]]]):
|
|
12
|
+
return {"inline_keyboard": buttons}
|
|
13
|
+
|
|
14
|
+
def remove_keyboard():
|
|
15
|
+
return {"remove_keyboard": True}
|
|
16
|
+
|
|
17
|
+
def prepare_upload_file(file_input):
|
|
18
|
+
if isinstance(file_input, str):
|
|
19
|
+
if file_input.startswith(('http://', 'https://')):
|
|
20
|
+
return None, file_input
|
|
21
|
+
if os.path.isfile(file_input):
|
|
22
|
+
return os.path.basename(file_input), open(file_input, 'rb')
|
|
23
|
+
return None, file_input
|
|
24
|
+
elif isinstance(file_input, bytes):
|
|
25
|
+
return "file.bin", file_input
|
|
26
|
+
raise ValueError("نوع فایل پشتیبانی نمیشود")
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: botbaleirp
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: کتابخانه کامل پایتون برای API بازوی بله
|
|
5
|
+
Author: Mohammad Latifi
|
|
6
|
+
Requires-Python: >=3.7
|
|
7
|
+
Requires-Dist: requests>=2.25.0
|
|
8
|
+
Dynamic: author
|
|
9
|
+
Dynamic: requires-dist
|
|
10
|
+
Dynamic: requires-python
|
|
11
|
+
Dynamic: summary
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
setup.py
|
|
2
|
+
botbaleirp/__init__.py
|
|
3
|
+
botbaleirp/bale_types.py
|
|
4
|
+
botbaleirp/bot.py
|
|
5
|
+
botbaleirp/errors.py
|
|
6
|
+
botbaleirp/utils.py
|
|
7
|
+
botbaleirp.egg-info/PKG-INFO
|
|
8
|
+
botbaleirp.egg-info/SOURCES.txt
|
|
9
|
+
botbaleirp.egg-info/dependency_links.txt
|
|
10
|
+
botbaleirp.egg-info/requires.txt
|
|
11
|
+
botbaleirp.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
requests>=2.25.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
botbaleirp
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from setuptools import setup
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="botbaleirp",
|
|
5
|
+
version="0.0.1",
|
|
6
|
+
author="Mohammad Latifi",
|
|
7
|
+
description="کتابخانه کامل پایتون برای API بازوی بله",
|
|
8
|
+
packages=["botbaleirp"],
|
|
9
|
+
install_requires=["requests>=2.25.0"],
|
|
10
|
+
python_requires=">=3.7",
|
|
11
|
+
)
|