maxbot-api-client-python 1.1.2__py3-none-any.whl → 2.0.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.
- maxbot_api_client_python/__init__.py +2 -1
- maxbot_api_client_python/api.py +2 -1
- maxbot_api_client_python/client.py +80 -82
- maxbot_api_client_python/exceptions.py +1 -1
- maxbot_api_client_python/tools/bots.py +19 -15
- maxbot_api_client_python/tools/chats.py +168 -134
- maxbot_api_client_python/tools/helpers.py +87 -62
- maxbot_api_client_python/tools/messages.py +83 -67
- maxbot_api_client_python/tools/subscriptions.py +44 -36
- maxbot_api_client_python/tools/uploads.py +41 -15
- maxbot_api_client_python/types/constants.py +1 -1
- maxbot_api_client_python/types/models.py +82 -65
- maxbot_api_client_python/utils.py +3 -1
- {maxbot_api_client_python-1.1.2.dist-info → maxbot_api_client_python-2.0.0.dist-info}/METADATA +35 -46
- maxbot_api_client_python-2.0.0.dist-info/RECORD +20 -0
- maxbot_api_client_python-1.1.2.dist-info/RECORD +0 -20
- {maxbot_api_client_python-1.1.2.dist-info → maxbot_api_client_python-2.0.0.dist-info}/WHEEL +0 -0
- {maxbot_api_client_python-1.1.2.dist-info → maxbot_api_client_python-2.0.0.dist-info}/licenses/LICENSE +0 -0
- {maxbot_api_client_python-1.1.2.dist-info → maxbot_api_client_python-2.0.0.dist-info}/top_level.txt +0 -0
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import aiofiles, asyncio, httpx, logging, mimetypes, os, time
|
|
1
|
+
import aiofiles, asyncio, httpx, logging, mimetypes, os, time, re
|
|
2
|
+
from aiofiles import tempfile
|
|
2
3
|
from typing import Any, List, Optional
|
|
3
4
|
from urllib.parse import urlparse
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
|
|
7
|
+
from maxbot_api_client_python.exceptions import MaxBotError
|
|
6
8
|
from maxbot_api_client_python.tools.uploads import Uploads
|
|
7
|
-
from maxbot_api_client_python.client import Client
|
|
9
|
+
from maxbot_api_client_python.client import Client
|
|
8
10
|
from maxbot_api_client_python.types.constants import AttachmentType, Paths, UploadType
|
|
9
11
|
from maxbot_api_client_python.types.models import Message, SendFileReq, SendMessageReq, UploadFileReq, Attachment
|
|
10
12
|
|
|
@@ -15,66 +17,74 @@ class Helpers:
|
|
|
15
17
|
self.client = client
|
|
16
18
|
self.uploads = Uploads(client)
|
|
17
19
|
|
|
18
|
-
def
|
|
20
|
+
def send_file(self, **kwargs: Any) -> Optional[Message]:
|
|
19
21
|
"""
|
|
20
22
|
A helper that simplifies sending files to a chat.
|
|
21
23
|
It automatically determines whether the provided file_source is a direct URL or a local file path.
|
|
22
24
|
|
|
23
25
|
Example:
|
|
24
26
|
# Sending a file via URL:
|
|
25
|
-
response =
|
|
27
|
+
response = bot.helpers.send_file(
|
|
26
28
|
chat_id=123456789,
|
|
27
29
|
text="Check out this image!",
|
|
28
30
|
file_source="https://example.com/image.png"
|
|
29
31
|
)
|
|
30
32
|
|
|
31
33
|
# Sending a local file:
|
|
32
|
-
response =
|
|
34
|
+
response = bot.helpers.send_file(
|
|
33
35
|
chat_id=123456789,
|
|
34
36
|
text="Here is the report.",
|
|
35
37
|
file_source="/local/path/to/report.pdf"
|
|
36
38
|
)
|
|
37
39
|
"""
|
|
38
40
|
req = SendFileReq(**kwargs)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
is_url = urlparse(req.file_source).scheme in ("http", "https")
|
|
42
|
+
if not is_url and not os.path.exists(req.file_source):
|
|
43
|
+
raise ValueError("Invalid file path or URL.")
|
|
44
|
+
|
|
45
|
+
if urlparse(req.file_source).scheme in ("http", "https"):
|
|
46
|
+
return self._send_file_by_url(req)
|
|
47
|
+
|
|
48
|
+
return self._send_file_by_upload(req)
|
|
42
49
|
|
|
43
|
-
def
|
|
50
|
+
def _send_file_by_url(self, req: SendFileReq) -> Optional[Message]:
|
|
44
51
|
ext = self._get_extension(req.file_source)
|
|
45
52
|
upload_type = self._determine_upload_type(ext)
|
|
46
53
|
|
|
47
54
|
if upload_type == UploadType.IMAGE:
|
|
48
55
|
attachment = Attachment(type=AttachmentType.IMAGE, payload={"url": req.file_source})
|
|
49
|
-
return self.
|
|
56
|
+
return self._send_file_internal(req, attachment)
|
|
50
57
|
|
|
51
58
|
temp_path = None
|
|
52
59
|
try:
|
|
53
60
|
temp_path = self._download_temp_file(req.file_source)
|
|
54
61
|
req.file_source = temp_path
|
|
55
|
-
return self.
|
|
62
|
+
return self._send_file_by_upload(req)
|
|
56
63
|
except Exception as e:
|
|
57
64
|
logger.error(f"File processing/upload error: {e}")
|
|
58
|
-
|
|
65
|
+
raise
|
|
59
66
|
finally:
|
|
60
|
-
if temp_path
|
|
61
|
-
|
|
67
|
+
if temp_path:
|
|
68
|
+
try:
|
|
69
|
+
os.remove(temp_path)
|
|
70
|
+
except FileNotFoundError:
|
|
71
|
+
pass
|
|
62
72
|
|
|
63
|
-
def
|
|
73
|
+
def _send_file_by_upload(self, req: SendFileReq) -> Optional[Message]:
|
|
64
74
|
ext = self._get_extension(req.file_source)
|
|
65
75
|
upload_type = self._determine_upload_type(ext)
|
|
66
76
|
|
|
67
77
|
upload_req = UploadFileReq(type=upload_type, file_path=req.file_source)
|
|
68
|
-
upload_resp = self.uploads.
|
|
78
|
+
upload_resp = self.uploads.upload_file(**upload_req.model_dump(exclude_none=True))
|
|
69
79
|
|
|
70
80
|
if not upload_resp or not upload_resp.token:
|
|
71
81
|
logger.error("Upload failed: No token returned.")
|
|
72
82
|
return None
|
|
73
83
|
|
|
74
84
|
attachment = self._build_attachment_from_token(upload_type, upload_resp.token, Path(req.file_source).name)
|
|
75
|
-
return self.
|
|
85
|
+
return self._send_file_internal(req, attachment)
|
|
76
86
|
|
|
77
|
-
def
|
|
87
|
+
def _send_file_internal(self, req: SendFileReq, attachment: Attachment) -> Message:
|
|
78
88
|
attachments: List[Attachment] = req.attachments or []
|
|
79
89
|
attachments.append(attachment)
|
|
80
90
|
|
|
@@ -89,13 +99,15 @@ class Helpers:
|
|
|
89
99
|
disable_link_preview=req.disable_link_preview
|
|
90
100
|
)
|
|
91
101
|
|
|
102
|
+
query, payload = self.client.split_request(request_data)
|
|
92
103
|
last_err: Optional[Exception] = None
|
|
104
|
+
|
|
93
105
|
for _ in range(self.client.max_retries):
|
|
94
106
|
try:
|
|
95
|
-
return
|
|
96
|
-
except
|
|
107
|
+
return self.client.decode("POST", Paths.MESSAGES, Message, query=query, payload=payload)
|
|
108
|
+
except MaxBotError as e:
|
|
97
109
|
last_err = e
|
|
98
|
-
if "not.ready" in str(e).lower():
|
|
110
|
+
if e.status_code == 422 or "not.ready" in str(e.response).lower():
|
|
99
111
|
time.sleep(self.client.retry_delay_sec)
|
|
100
112
|
continue
|
|
101
113
|
break
|
|
@@ -104,73 +116,81 @@ class Helpers:
|
|
|
104
116
|
raise last_err
|
|
105
117
|
raise Exception("Unknown error in sendFileInternal")
|
|
106
118
|
|
|
107
|
-
async def
|
|
119
|
+
async def send_file_async(self, **kwargs: Any) -> Optional[Message]:
|
|
108
120
|
"""
|
|
109
|
-
Async version of
|
|
121
|
+
Async version of send_file.
|
|
110
122
|
|
|
111
123
|
Example:
|
|
112
124
|
# Sending a local file asynchronously:
|
|
113
|
-
response = await
|
|
125
|
+
response = await bot.helpers.send_file_async(
|
|
114
126
|
chat_id=123456789,
|
|
115
127
|
text="Here is the report.",
|
|
116
128
|
file_source="/local/path/to/report.pdf"
|
|
117
129
|
)
|
|
118
130
|
"""
|
|
119
131
|
req = SendFileReq(**kwargs)
|
|
120
|
-
if
|
|
121
|
-
return await self.
|
|
122
|
-
|
|
132
|
+
if urlparse(req.file_source).scheme in ("http", "https"):
|
|
133
|
+
return await self._send_file_by_url_async(req)
|
|
134
|
+
|
|
135
|
+
return await self._send_file_by_upload_async(req)
|
|
123
136
|
|
|
124
|
-
async def
|
|
137
|
+
async def _send_file_by_url_async(self, req: SendFileReq) -> Optional[Message]:
|
|
125
138
|
ext = self._get_extension(req.file_source)
|
|
126
139
|
upload_type = self._determine_upload_type(ext)
|
|
127
140
|
|
|
128
141
|
if upload_type == UploadType.IMAGE:
|
|
129
142
|
attachment = Attachment(type=AttachmentType.IMAGE, payload={"url": req.file_source})
|
|
130
|
-
return await self.
|
|
143
|
+
return await self._send_file_internal_async(req, attachment)
|
|
131
144
|
|
|
132
145
|
temp_path = None
|
|
133
146
|
try:
|
|
134
147
|
temp_path = await self._download_temp_file_async(req.file_source)
|
|
135
148
|
req.file_source = temp_path
|
|
136
|
-
return await self.
|
|
149
|
+
return await self._send_file_by_upload_async(req)
|
|
137
150
|
except Exception as e:
|
|
138
151
|
logger.error(f"Async file processing/upload error: {e}")
|
|
139
|
-
|
|
152
|
+
raise
|
|
140
153
|
finally:
|
|
141
154
|
if temp_path and os.path.exists(temp_path):
|
|
142
|
-
|
|
155
|
+
try:
|
|
156
|
+
await aiofiles.os.remove(temp_path)
|
|
157
|
+
except OSError as e:
|
|
158
|
+
logger.error(f"Failed to cleanup temp file: {e}")
|
|
143
159
|
|
|
144
|
-
async def
|
|
160
|
+
async def _send_file_by_upload_async(self, req: SendFileReq) -> Optional[Message]:
|
|
145
161
|
ext = self._get_extension(req.file_source)
|
|
146
162
|
u_type = self._determine_upload_type(ext)
|
|
147
163
|
|
|
148
164
|
upload_req = UploadFileReq(type=u_type, file_path=req.file_source)
|
|
149
|
-
upload_resp = await self.uploads.
|
|
165
|
+
upload_resp = await self.uploads.upload_file_async(**upload_req.model_dump(exclude_none=True))
|
|
150
166
|
|
|
151
167
|
if not upload_resp or not upload_resp.token:
|
|
152
168
|
return None
|
|
153
169
|
|
|
154
170
|
attachment = self._build_attachment_from_token(u_type, upload_resp.token, Path(req.file_source).name)
|
|
155
|
-
return await self.
|
|
171
|
+
return await self._send_file_internal_async(req, attachment)
|
|
156
172
|
|
|
157
|
-
async def
|
|
173
|
+
async def _send_file_internal_async(self, req: SendFileReq, attachment: Attachment) -> Message:
|
|
158
174
|
attachments: List[Attachment] = req.attachments or []
|
|
159
175
|
attachments.append(attachment)
|
|
160
176
|
|
|
161
177
|
request_data = SendMessageReq(
|
|
162
|
-
|
|
163
|
-
|
|
178
|
+
user_id=req.user_id,
|
|
179
|
+
chat_id=req.chat_id,
|
|
180
|
+
text=req.text,
|
|
181
|
+
format=req.format,
|
|
182
|
+
attachments=attachments,
|
|
183
|
+
notify=req.notify,
|
|
184
|
+
link=req.link,
|
|
185
|
+
disable_link_preview=req.disable_link_preview
|
|
164
186
|
)
|
|
165
187
|
|
|
188
|
+
query, payload = self.client.split_request(request_data)
|
|
166
189
|
last_err: Optional[Exception] = None
|
|
190
|
+
|
|
167
191
|
for _ in range(self.client.max_retries):
|
|
168
192
|
try:
|
|
169
|
-
return await adecode(
|
|
170
|
-
self.client, "POST", Paths.MESSAGES, Message,
|
|
171
|
-
query=request_data.model_dump(exclude_none=True),
|
|
172
|
-
payload=request_data
|
|
173
|
-
)
|
|
193
|
+
return await self.client.adecode("POST", Paths.MESSAGES, Message, query=query, payload=payload)
|
|
174
194
|
except Exception as e:
|
|
175
195
|
last_err = e
|
|
176
196
|
if "not.ready" in str(e).lower():
|
|
@@ -181,13 +201,6 @@ class Helpers:
|
|
|
181
201
|
if last_err:
|
|
182
202
|
raise last_err
|
|
183
203
|
raise Exception("Unknown error in sendFileInternalAsync")
|
|
184
|
-
|
|
185
|
-
def _is_url(self, source: str) -> bool:
|
|
186
|
-
try:
|
|
187
|
-
result = urlparse(source)
|
|
188
|
-
return all([result.scheme, result.netloc])
|
|
189
|
-
except ValueError:
|
|
190
|
-
return False
|
|
191
204
|
|
|
192
205
|
def _get_extension(self, source: str) -> str:
|
|
193
206
|
parsed = urlparse(source)
|
|
@@ -202,6 +215,10 @@ class Helpers:
|
|
|
202
215
|
if ext in {".mp3", ".ogg", ".wav"}:
|
|
203
216
|
return UploadType.AUDIO
|
|
204
217
|
return UploadType.FILE
|
|
218
|
+
|
|
219
|
+
def _sanitize_filename(self, filename: str) -> str:
|
|
220
|
+
base = os.path.basename(filename)
|
|
221
|
+
return re.sub(r'[^a-zA-Z0-9.\-_]', '_', base)
|
|
205
222
|
|
|
206
223
|
def _build_attachment_from_token(self, u_type: UploadType, token: str, filename: str) -> Attachment:
|
|
207
224
|
payload: dict[str, Any] = {"token": token}
|
|
@@ -211,14 +228,17 @@ class Helpers:
|
|
|
211
228
|
|
|
212
229
|
def _download_temp_file(self, url_str: str) -> str:
|
|
213
230
|
headers = {"User-Agent": "maxbot-client/1.0"}
|
|
214
|
-
with httpx.Client() as client:
|
|
231
|
+
with httpx.Client(follow_redirects=True, max_redirects=3) as client:
|
|
232
|
+
|
|
215
233
|
with client.stream("GET", url_str, headers=headers, follow_redirects=True) as resp:
|
|
216
234
|
resp.raise_for_status()
|
|
217
235
|
|
|
218
236
|
content_disp = resp.headers.get("Content-Disposition", "")
|
|
219
237
|
filename = None
|
|
220
238
|
if "filename=" in content_disp:
|
|
221
|
-
|
|
239
|
+
raw_part = content_disp.split("filename=")[1].split(";")[0]
|
|
240
|
+
raw_filename = raw_part.strip('"').strip("'")
|
|
241
|
+
filename = self._sanitize_filename(raw_filename)
|
|
222
242
|
|
|
223
243
|
if not filename:
|
|
224
244
|
content_type = resp.headers.get("Content-Type", "")
|
|
@@ -227,14 +247,17 @@ class Helpers:
|
|
|
227
247
|
filename = f"file{ext}"
|
|
228
248
|
|
|
229
249
|
if not filename:
|
|
230
|
-
filename = Path(urlparse(url_str).path).name or "temp_file.bin"
|
|
231
|
-
|
|
232
|
-
temp_path = f"
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
250
|
+
filename = os.path.basename(Path(urlparse(url_str).path).name) or "temp_file.bin"
|
|
251
|
+
|
|
252
|
+
fd, temp_path = tempfile.mkstemp(prefix="temp_", suffix=f"_{os.path.basename(filename)}")
|
|
253
|
+
try:
|
|
254
|
+
with os.fdopen(fd, "wb") as f:
|
|
255
|
+
for chunk in resp.iter_bytes(chunk_size=8192):
|
|
256
|
+
f.write(chunk)
|
|
257
|
+
return temp_path
|
|
258
|
+
except Exception:
|
|
259
|
+
os.remove(temp_path)
|
|
260
|
+
raise
|
|
238
261
|
|
|
239
262
|
async def _download_temp_file_async(self, url_str: str) -> str:
|
|
240
263
|
headers = {"User-Agent": "maxbot-client/1.0"}
|
|
@@ -245,13 +268,15 @@ class Helpers:
|
|
|
245
268
|
content_type = resp.headers.get("Content-Type", "").split(";")[0]
|
|
246
269
|
extension = mimetypes.guess_extension(content_type) or ".bin"
|
|
247
270
|
|
|
248
|
-
url_path_name = Path(urlparse(url_str).path).name
|
|
271
|
+
url_path_name = os.path.basename(Path(urlparse(url_str).path).name)
|
|
249
272
|
if url_path_name == "uc" or not url_path_name:
|
|
250
273
|
filename = f"file{extension}"
|
|
251
274
|
else:
|
|
252
275
|
filename = url_path_name if "." in url_path_name else f"{url_path_name}{extension}"
|
|
253
276
|
|
|
254
|
-
|
|
277
|
+
temp_file = tempfile.NamedTemporaryFile(prefix="temp_", suffix=f"_{os.path.basename(filename)}", delete=False)
|
|
278
|
+
temp_path = temp_file.name
|
|
279
|
+
temp_file.close()
|
|
255
280
|
|
|
256
281
|
async with aiofiles.open(temp_path, "wb") as f:
|
|
257
282
|
async for chunk in resp.aiter_bytes(chunk_size=8192):
|
|
@@ -1,194 +1,210 @@
|
|
|
1
|
-
from
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from maxbot_api_client_python.client import Client
|
|
2
4
|
from maxbot_api_client_python.types.constants import Paths
|
|
3
|
-
from maxbot_api_client_python.types import
|
|
5
|
+
from maxbot_api_client_python.types.models import AnswerCallbackReq, DeleteMessageReq, EditMessageReq, GetMessageReq, GetMessagesReq, GetVideoInfoReq, GetVideoInfoResp, Message, MessagesList, SendMessageReq, SendMessageResp, SimpleQueryResult
|
|
4
6
|
|
|
5
7
|
class Messages:
|
|
6
8
|
def __init__(self, client: Client):
|
|
7
9
|
self.client = client
|
|
8
10
|
|
|
9
|
-
def
|
|
11
|
+
def get_messages(self, **kwargs: Any) -> MessagesList:
|
|
10
12
|
"""
|
|
11
13
|
Retrieves a list of messages.
|
|
12
14
|
It can fetch messages belonging to a specific ChatID or by an exact list of MessageIDs.
|
|
13
15
|
|
|
14
16
|
Example:
|
|
15
17
|
# Fetch messages by Chat ID
|
|
16
|
-
response =
|
|
18
|
+
response = bot.messages.get_messages(chat_id=123456)
|
|
17
19
|
|
|
18
20
|
# Fetch specific messages:
|
|
19
|
-
response =
|
|
21
|
+
response = bot.messages.get_messages(message_ids=["mid:1", "mid:2"])
|
|
20
22
|
"""
|
|
21
|
-
req =
|
|
22
|
-
|
|
23
|
+
req = GetMessagesReq(**kwargs)
|
|
24
|
+
query, payload = self.client.split_request(req)
|
|
25
|
+
return self.client.decode("GET", Paths.MESSAGES, MessagesList, query=query, payload=payload)
|
|
23
26
|
|
|
24
|
-
def
|
|
27
|
+
def send_message(self, **kwargs: Any) -> SendMessageResp:
|
|
25
28
|
"""
|
|
26
29
|
Sends a text message or attachment to a specific user or chat.
|
|
27
30
|
If Notify is False, no push notification will be sent to the user.
|
|
28
31
|
|
|
29
32
|
Example:
|
|
30
|
-
response =
|
|
33
|
+
response = bot.messages.send_message(
|
|
31
34
|
chat_id=123456,
|
|
32
35
|
text="Hello, world!",
|
|
33
36
|
notify=True
|
|
34
37
|
)
|
|
35
38
|
"""
|
|
36
|
-
req =
|
|
37
|
-
|
|
39
|
+
req = SendMessageReq(**kwargs)
|
|
40
|
+
query, payload = self.client.split_request(req)
|
|
41
|
+
return self.client.decode("POST", Paths.MESSAGES, SendMessageResp, query=query, payload=payload)
|
|
38
42
|
|
|
39
|
-
def
|
|
43
|
+
def edit_message(self, **kwargs: Any) -> SimpleQueryResult:
|
|
40
44
|
"""
|
|
41
45
|
Modifies the content of a previously sent message.
|
|
42
46
|
|
|
43
47
|
Example:
|
|
44
|
-
response =
|
|
48
|
+
response = bot.messages.edit_message(
|
|
45
49
|
message_id="mid:987654321...",
|
|
46
50
|
text="Updated message text!",
|
|
47
51
|
format="HTML"
|
|
48
52
|
)
|
|
49
53
|
"""
|
|
50
|
-
req =
|
|
51
|
-
|
|
54
|
+
req = EditMessageReq(**kwargs)
|
|
55
|
+
query, payload = self.client.split_request(req)
|
|
56
|
+
return self.client.decode("PUT", Paths.MESSAGES, SimpleQueryResult, query=query, payload=payload)
|
|
52
57
|
|
|
53
|
-
def
|
|
58
|
+
def delete_message(self, **kwargs: Any) -> SimpleQueryResult:
|
|
54
59
|
"""
|
|
55
60
|
Removes a previously sent message by its ID.
|
|
56
61
|
|
|
57
62
|
Example:
|
|
58
|
-
response =
|
|
63
|
+
response = bot.messages.delete_message(
|
|
59
64
|
message_id="mid:987654321..."
|
|
60
65
|
)
|
|
61
66
|
"""
|
|
62
|
-
req =
|
|
63
|
-
|
|
67
|
+
req = DeleteMessageReq(**kwargs)
|
|
68
|
+
query, payload = self.client.split_request(req)
|
|
69
|
+
return self.client.decode("DELETE", Paths.MESSAGES, SimpleQueryResult, query=query, payload=payload)
|
|
64
70
|
|
|
65
|
-
def
|
|
71
|
+
def get_message(self, **kwargs: Any) -> Message:
|
|
66
72
|
"""
|
|
67
73
|
Retrieves full information about a message by its ID.
|
|
68
74
|
|
|
69
75
|
Example:
|
|
70
|
-
response =
|
|
76
|
+
response = bot.messages.get_message(
|
|
71
77
|
message_id="mid:987654321..."
|
|
72
78
|
)
|
|
73
79
|
"""
|
|
74
|
-
req =
|
|
80
|
+
req = GetMessageReq(**kwargs)
|
|
75
81
|
path = f"{Paths.MESSAGES}/{req.message_id}"
|
|
76
|
-
|
|
82
|
+
query, payload = self.client.split_request(req)
|
|
83
|
+
return self.client.decode("GET", path, Message, query=query, payload=payload)
|
|
77
84
|
|
|
78
|
-
def
|
|
85
|
+
def get_video_info(self, **kwargs: Any) -> GetVideoInfoResp:
|
|
79
86
|
"""
|
|
80
87
|
Retrieves metadata and the processing status for an uploaded video.
|
|
81
88
|
|
|
82
89
|
Example:
|
|
83
|
-
response =
|
|
90
|
+
response = bot.messages.get_video_info(
|
|
84
91
|
video_token="vtok_abc123xyz..."
|
|
85
92
|
)
|
|
86
93
|
"""
|
|
87
|
-
req =
|
|
94
|
+
req = GetVideoInfoReq(**kwargs)
|
|
88
95
|
path = f"{Paths.VIDEOS}/{req.video_token}"
|
|
89
|
-
|
|
96
|
+
query, payload = self.client.split_request(req)
|
|
97
|
+
return self.client.decode("GET", path, GetVideoInfoResp, query=query, payload=payload)
|
|
90
98
|
|
|
91
|
-
def
|
|
99
|
+
def answer_callback(self, **kwargs: Any) -> SimpleQueryResult:
|
|
92
100
|
"""
|
|
93
101
|
Acknowledges and responds to a user clicking an inline button.
|
|
94
102
|
|
|
95
103
|
Example:
|
|
96
|
-
response =
|
|
104
|
+
response = bot.messages.answer_callback(
|
|
97
105
|
callback_id="cbk_12345...",
|
|
98
106
|
message=NewMessageBody(text="Action confirmed!")
|
|
99
107
|
)
|
|
100
108
|
"""
|
|
101
|
-
req =
|
|
102
|
-
|
|
109
|
+
req = AnswerCallbackReq(**kwargs)
|
|
110
|
+
query, payload = self.client.split_request(req)
|
|
111
|
+
return self.client.decode("POST", Paths.ANSWERS, SimpleQueryResult, query=query, payload=payload)
|
|
103
112
|
|
|
104
|
-
async def
|
|
105
|
-
"""Async version of
|
|
113
|
+
async def get_messages_async(self, **kwargs: Any) -> MessagesList:
|
|
114
|
+
"""Async version of get_messages.
|
|
106
115
|
|
|
107
116
|
Example:
|
|
108
117
|
# Fetch messages by Chat ID
|
|
109
|
-
response = await
|
|
118
|
+
response = await bot.messages.get_messages_async(chat_id=123456)
|
|
110
119
|
|
|
111
120
|
# Fetch specific messages:
|
|
112
|
-
response = await
|
|
121
|
+
response = await bot.messages.get_messages_async(message_ids=["mid:1", "mid:2"])
|
|
113
122
|
"""
|
|
114
|
-
req =
|
|
115
|
-
|
|
123
|
+
req = GetMessagesReq(**kwargs)
|
|
124
|
+
query, payload = self.client.split_request(req)
|
|
125
|
+
return await self.client.adecode("GET", Paths.MESSAGES, MessagesList, query=query, payload=payload)
|
|
116
126
|
|
|
117
|
-
async def
|
|
127
|
+
async def send_message_async(self, **kwargs: Any) -> SendMessageResp:
|
|
118
128
|
"""
|
|
119
|
-
Async version of
|
|
129
|
+
Async version of send_message.
|
|
120
130
|
|
|
121
131
|
Example:
|
|
122
|
-
response = await
|
|
132
|
+
response = await bot.messages.send_message_async(
|
|
123
133
|
chat_id=123456,
|
|
124
134
|
text="Hello, world!",
|
|
125
135
|
notify=True
|
|
126
136
|
)
|
|
127
137
|
"""
|
|
128
|
-
req =
|
|
129
|
-
|
|
138
|
+
req = SendMessageReq(**kwargs)
|
|
139
|
+
query, payload = self.client.split_request(req)
|
|
140
|
+
return await self.client.adecode("POST", Paths.MESSAGES, SendMessageResp, query=query, payload=payload)
|
|
130
141
|
|
|
131
|
-
async def
|
|
142
|
+
async def edit_message_async(self, **kwargs: Any) -> SimpleQueryResult:
|
|
132
143
|
"""
|
|
133
|
-
Async version of
|
|
144
|
+
Async version of edit_message.
|
|
134
145
|
|
|
135
146
|
Example:
|
|
136
|
-
response = await
|
|
147
|
+
response = await bot.messages.edit_message_async(
|
|
137
148
|
message_id="mid:987654321...",
|
|
138
149
|
text="Updated message text!",
|
|
139
150
|
format="HTML"
|
|
140
151
|
)
|
|
141
152
|
"""
|
|
142
|
-
req =
|
|
143
|
-
|
|
153
|
+
req = EditMessageReq(**kwargs)
|
|
154
|
+
query, payload = self.client.split_request(req)
|
|
155
|
+
return await self.client.adecode("PUT", Paths.MESSAGES, SimpleQueryResult, query=query, payload=payload)
|
|
144
156
|
|
|
145
|
-
async def
|
|
157
|
+
async def delete_message_async(self, **kwargs: Any) -> SimpleQueryResult:
|
|
146
158
|
"""
|
|
147
|
-
Async version of
|
|
159
|
+
Async version of delete_message.
|
|
148
160
|
|
|
149
161
|
Example:
|
|
150
|
-
response = await
|
|
162
|
+
response = await bot.messages.delete_message_async(
|
|
151
163
|
message_id="mid:987654321..."
|
|
152
164
|
)
|
|
153
165
|
"""
|
|
154
|
-
req =
|
|
155
|
-
|
|
166
|
+
req = DeleteMessageReq(**kwargs)
|
|
167
|
+
query, payload = self.client.split_request(req)
|
|
168
|
+
return await self.client.adecode("DELETE", Paths.MESSAGES, SimpleQueryResult, query=query, payload=payload)
|
|
156
169
|
|
|
157
|
-
async def
|
|
170
|
+
async def get_message_async(self, **kwargs: Any) -> Message:
|
|
158
171
|
"""
|
|
159
|
-
Async version of
|
|
172
|
+
Async version of get_message.
|
|
160
173
|
|
|
161
174
|
Example:
|
|
162
|
-
response = await
|
|
175
|
+
response = await bot.messages.get_message_async(
|
|
163
176
|
message_id="mid:987654321..."
|
|
164
177
|
)
|
|
165
178
|
"""
|
|
166
|
-
req =
|
|
179
|
+
req = GetMessageReq(**kwargs)
|
|
167
180
|
path = f"{Paths.MESSAGES}/{req.message_id}"
|
|
168
|
-
|
|
181
|
+
query, payload = self.client.split_request(req)
|
|
182
|
+
return await self.client.adecode("GET", path, Message, query=query, payload=payload)
|
|
169
183
|
|
|
170
|
-
async def
|
|
184
|
+
async def get_video_info_async(self, **kwargs: Any) -> GetVideoInfoResp:
|
|
171
185
|
"""
|
|
172
|
-
Async version of
|
|
186
|
+
Async version of get_video.
|
|
173
187
|
|
|
174
188
|
Example:
|
|
175
|
-
response = await
|
|
189
|
+
response = await bot.messages.get_video_info_async(
|
|
176
190
|
video_token="vtok_abc123xyz..."
|
|
177
191
|
)
|
|
178
192
|
"""
|
|
179
|
-
req =
|
|
193
|
+
req = GetVideoInfoReq(**kwargs)
|
|
180
194
|
path = f"{Paths.VIDEOS}/{req.video_token}"
|
|
181
|
-
|
|
195
|
+
query, payload = self.client.split_request(req)
|
|
196
|
+
return await self.client.adecode("GET", path, GetVideoInfoResp, query=query, payload=payload)
|
|
182
197
|
|
|
183
|
-
async def
|
|
198
|
+
async def answer_callback_async(self, **kwargs: Any) -> SimpleQueryResult:
|
|
184
199
|
"""
|
|
185
|
-
Async version of
|
|
200
|
+
Async version of answer_callback.
|
|
186
201
|
|
|
187
202
|
Example:
|
|
188
|
-
response = await
|
|
203
|
+
response = await bot.messages.answer_callback_async(
|
|
189
204
|
callback_id="cbk_12345...",
|
|
190
205
|
message=NewMessageBody(text="Action confirmed!")
|
|
191
206
|
)
|
|
192
207
|
"""
|
|
193
|
-
req =
|
|
194
|
-
|
|
208
|
+
req = AnswerCallbackReq(**kwargs)
|
|
209
|
+
query, payload = self.client.split_request(req)
|
|
210
|
+
return await self.client.adecode("POST", Paths.ANSWERS, SimpleQueryResult, query=query, payload=payload)
|