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