maxapi-python 1.1.3__py3-none-any.whl → 1.1.5__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.
- {maxapi_python-1.1.3.dist-info → maxapi_python-1.1.5.dist-info}/METADATA +2 -2
- {maxapi_python-1.1.3.dist-info → maxapi_python-1.1.5.dist-info}/RECORD +11 -11
- pymax/filters.py +4 -0
- pymax/mixins/group.py +1 -1
- pymax/mixins/message.py +85 -11
- pymax/mixins/socket.py +1 -3
- pymax/mixins/websocket.py +1 -1
- pymax/payloads.py +10 -0
- pymax/types.py +56 -11
- {maxapi_python-1.1.3.dist-info → maxapi_python-1.1.5.dist-info}/WHEEL +0 -0
- {maxapi_python-1.1.3.dist-info → maxapi_python-1.1.5.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: maxapi-python
|
3
|
-
Version: 1.1.
|
3
|
+
Version: 1.1.5
|
4
4
|
Summary: Python wrapper для API мессенджера Max
|
5
5
|
Project-URL: Homepage, https://github.com/noxzion/PyMax
|
6
6
|
Project-URL: Repository, https://github.com/noxzion/PyMax
|
@@ -17,7 +17,7 @@ Requires-Dist: aiohttp>=3.12.15
|
|
17
17
|
Requires-Dist: lz4>=4.4.4
|
18
18
|
Requires-Dist: msgpack>=1.1.1
|
19
19
|
Requires-Dist: sqlmodel>=0.0.24
|
20
|
-
Requires-Dist: websockets>=
|
20
|
+
Requires-Dist: websockets>=15.0
|
21
21
|
Description-Content-Type: text/markdown
|
22
22
|
|
23
23
|
<p align="center">
|
@@ -3,26 +3,26 @@ pymax/core.py,sha256=6fqnP-eAgbUTM6F0Kj09TPJ3IOgvkHz5EsjJTI18r5A,7813
|
|
3
3
|
pymax/crud.py,sha256=Mk-c87GItS91BlJu6INDbw1-ovXyoB2D9rXHK8voxpU,3207
|
4
4
|
pymax/exceptions.py,sha256=msS11MD7qZPm0qZ6O8fobTm-GTldm2IA3uQLTX6eDxc,919
|
5
5
|
pymax/files.py,sha256=Tpv-43gS7I4Pwlaimb8mZ2B-ZkF3aMsrLYT20NPaqhE,2656
|
6
|
-
pymax/filters.py,sha256=
|
6
|
+
pymax/filters.py,sha256=fxC3Bl5AqrB8BSdN-CtiLWucbHCRA2IODpsOy2NagGU,1471
|
7
7
|
pymax/interfaces.py,sha256=_D6iMQI74Gdtl6-HMoE1acRFRHeITgOZPVFpt5pvoow,2394
|
8
8
|
pymax/models.py,sha256=PsPGbOkERxesZZltjNrmqhOfRcO44Is2ThbEToREcB8,201
|
9
9
|
pymax/navigation.py,sha256=16c1_FZrw24uFlP6W5-F8OrEQE73bkQA3HSFqTdBtgo,5725
|
10
|
-
pymax/payloads.py,sha256=
|
10
|
+
pymax/payloads.py,sha256=t-6xM3s8laQqBWyVdcQNV080sjfRsOtbQ-o6CKpAh20,4087
|
11
11
|
pymax/static.py,sha256=wwSV1ue5s5buqWz6TvCzjzN2ZWI-wITposTRvcS151g,4738
|
12
|
-
pymax/types.py,sha256=
|
12
|
+
pymax/types.py,sha256=2huOPuGxwka_6s-Fw-7KbeAAoiFJrB7e07ArBKIRA6w,19020
|
13
13
|
pymax/utils.py,sha256=F2TdoWfSwDLeh2uIcMIE_GTdXd7hU7gWti2i5P727bA,1364
|
14
14
|
pymax/mixins/__init__.py,sha256=-PSMwTVioS-VTy-EGfV-epaKFLy58R4N2b-rX6wJf-M,649
|
15
15
|
pymax/mixins/auth.py,sha256=vTNSZ6AunvDIMPQAvgYozpIZaCWMYiMDiabCBI7Sm6c,3079
|
16
16
|
pymax/mixins/channel.py,sha256=Stnf63GPtlQnsMPVEC9P0oardEOz50I4DCXN5H5s1SM,823
|
17
|
-
pymax/mixins/group.py,sha256=
|
17
|
+
pymax/mixins/group.py,sha256=NFdq6VExTKR80tE9XzVBjuG_eRMKEdYSm2HZop5yPYE,7809
|
18
18
|
pymax/mixins/handler.py,sha256=I1iNPaEgpvFnphaxV6liLwVaBCJ8sN6-h7908-_tPFk,2104
|
19
|
-
pymax/mixins/message.py,sha256=
|
19
|
+
pymax/mixins/message.py,sha256=GtwhoZaX2JPadhE9wq7M0YHBV1V2jbBIFwtQVIWP8sY,12896
|
20
20
|
pymax/mixins/self.py,sha256=V0gbkY3jfX9fnd7v06n4_s7P3HTPcS1KNPqUzA0vNi8,1169
|
21
|
-
pymax/mixins/socket.py,sha256=
|
21
|
+
pymax/mixins/socket.py,sha256=UNMU1Fh9J3xDV76J2Mx8bVHXo0gcS81qocOw8MM0XXs,15643
|
22
22
|
pymax/mixins/telemetry.py,sha256=0sQl6kvFVxobLthNAPNS9LzMrwwzZFA1xmOnvfiHWos,3522
|
23
23
|
pymax/mixins/user.py,sha256=U-epgvLruTDHBCrLDE0N0iWeOypGE1_SU8cKD3TE90U,3045
|
24
|
-
pymax/mixins/websocket.py,sha256=
|
25
|
-
maxapi_python-1.1.
|
26
|
-
maxapi_python-1.1.
|
27
|
-
maxapi_python-1.1.
|
28
|
-
maxapi_python-1.1.
|
24
|
+
pymax/mixins/websocket.py,sha256=L958bXTYh6U89jnmd0VWIUVtmJweUVFOMqjEuH8jWGo,10079
|
25
|
+
maxapi_python-1.1.5.dist-info/METADATA,sha256=k2lznWoJb4fgMJg_abFlOXE064a5_eZjbMDknokgZh8,5930
|
26
|
+
maxapi_python-1.1.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
27
|
+
maxapi_python-1.1.5.dist-info/licenses/LICENSE,sha256=oe-AGp86WMKawV4KmqF28Q0m-kGAhPfAOPrEUm4MnVw,1064
|
28
|
+
maxapi_python-1.1.5.dist-info/RECORD,,
|
pymax/filters.py
CHANGED
@@ -5,6 +5,7 @@ from .types import Message
|
|
5
5
|
class Filter:
|
6
6
|
def __init__(
|
7
7
|
self,
|
8
|
+
chat_id: int | None = None,
|
8
9
|
user_id: int | None = None,
|
9
10
|
text: list[str] | None = None,
|
10
11
|
status: MessageStatus | str | None = None,
|
@@ -12,6 +13,7 @@ class Filter:
|
|
12
13
|
text_contains: str | None = None,
|
13
14
|
reaction_info: bool | None = None,
|
14
15
|
) -> None:
|
16
|
+
self.chat_id = chat_id
|
15
17
|
self.user_id = user_id
|
16
18
|
self.text = text
|
17
19
|
self.status = status
|
@@ -20,6 +22,8 @@ class Filter:
|
|
20
22
|
self.text_contains = text_contains
|
21
23
|
|
22
24
|
def match(self, message: Message) -> bool:
|
25
|
+
if self.chat_id is not None and message.chat_id != self.chat_id:
|
26
|
+
return False
|
23
27
|
if self.user_id is not None and message.sender != self.user_id:
|
24
28
|
return False
|
25
29
|
if self.text is not None and any(
|
pymax/mixins/group.py
CHANGED
@@ -51,7 +51,7 @@ class GroupMixin(ClientProtocol):
|
|
51
51
|
return None
|
52
52
|
|
53
53
|
chat = Chat.from_dict(data["payload"]["chat"])
|
54
|
-
message = Message.from_dict(data["payload"]
|
54
|
+
message = Message.from_dict(data["payload"])
|
55
55
|
|
56
56
|
if chat:
|
57
57
|
cached_chat = await self._get_chat(chat.id)
|
pymax/mixins/message.py
CHANGED
@@ -15,9 +15,11 @@ from pymax.payloads import (
|
|
15
15
|
SendMessagePayload,
|
16
16
|
SendMessagePayloadMessage,
|
17
17
|
UploadPhotoPayload,
|
18
|
+
GetVideoPayload,
|
19
|
+
GetFilePayload,
|
18
20
|
)
|
19
21
|
from pymax.static import AttachType, Opcode
|
20
|
-
from pymax.types import Attach, Message
|
22
|
+
from pymax.types import Attach, Message, FileRequest, VideoRequest
|
21
23
|
|
22
24
|
|
23
25
|
class MessageMixin(ClientProtocol):
|
@@ -143,11 +145,7 @@ class MessageMixin(ClientProtocol):
|
|
143
145
|
self.logger.error("Send message error: %s", error)
|
144
146
|
print(data)
|
145
147
|
return None
|
146
|
-
msg = (
|
147
|
-
Message.from_dict(data["payload"]["message"])
|
148
|
-
if data.get("payload")
|
149
|
-
else None
|
150
|
-
)
|
148
|
+
msg = Message.from_dict(data["payload"]) if data.get("payload") else None
|
151
149
|
self.logger.debug("send_message result: %r", msg)
|
152
150
|
return msg
|
153
151
|
except Exception:
|
@@ -174,11 +172,7 @@ class MessageMixin(ClientProtocol):
|
|
174
172
|
data = await self._send_and_wait(opcode=Opcode.MSG_EDIT, payload=payload)
|
175
173
|
if error := data.get("payload", {}).get("error"):
|
176
174
|
self.logger.error("Edit message error: %s", error)
|
177
|
-
msg = (
|
178
|
-
Message.from_dict(data["payload"]["message"])
|
179
|
-
if data.get("payload")
|
180
|
-
else None
|
181
|
-
)
|
175
|
+
msg = Message.from_dict(data["payload"]) if data.get("payload") else None
|
182
176
|
self.logger.debug("edit_message result: %r", msg)
|
183
177
|
return msg
|
184
178
|
except Exception:
|
@@ -291,3 +285,83 @@ class MessageMixin(ClientProtocol):
|
|
291
285
|
except Exception:
|
292
286
|
self.logger.exception("Fetch history failed")
|
293
287
|
return None
|
288
|
+
|
289
|
+
|
290
|
+
async def get_video_by_id(
|
291
|
+
self,
|
292
|
+
chat_id: int,
|
293
|
+
message_id: int,
|
294
|
+
video_id: str,
|
295
|
+
) -> VideoRequest | None:
|
296
|
+
"""
|
297
|
+
Получает видео
|
298
|
+
|
299
|
+
Args:
|
300
|
+
chat_id (int): ID чата
|
301
|
+
message_id (int): ID сообщения
|
302
|
+
video_id (int): ID видео
|
303
|
+
|
304
|
+
Returns:
|
305
|
+
external (str): Странная ссылка из апи
|
306
|
+
cache (bool): True, если видео кэшировано
|
307
|
+
url (str): Ссылка на видео
|
308
|
+
"""
|
309
|
+
try:
|
310
|
+
self.logger.info(
|
311
|
+
"Getting video_id=%s message_id=%s", video_id, message_id
|
312
|
+
)
|
313
|
+
|
314
|
+
payload = GetVideoPayload(
|
315
|
+
chat_id=chat_id,
|
316
|
+
message_id=message_id,
|
317
|
+
video_id=video_id
|
318
|
+
).model_dump(by_alias=True)
|
319
|
+
|
320
|
+
data = await self._send_and_wait(opcode=Opcode.VIDEO_PLAY, payload=payload)
|
321
|
+
|
322
|
+
if error := data.get("payload", {}).get("error"):
|
323
|
+
self.logger.error("Get video error: %s", error)
|
324
|
+
|
325
|
+
video = VideoRequest.from_dict(data["payload"]) if data.get("payload") else None
|
326
|
+
self.logger.debug(" result: %r", video)
|
327
|
+
return video
|
328
|
+
except Exception:
|
329
|
+
self.logger.exception("Get video error")
|
330
|
+
return None
|
331
|
+
|
332
|
+
async def get_file_by_id(
|
333
|
+
self,
|
334
|
+
chat_id: int,
|
335
|
+
message_id: int,
|
336
|
+
file_id: str,
|
337
|
+
) -> FileRequest | None:
|
338
|
+
"""
|
339
|
+
Получает файл
|
340
|
+
|
341
|
+
Args:
|
342
|
+
chat_id (int): ID чата
|
343
|
+
message_id (int): ID сообщения
|
344
|
+
file_id (int): ID видео
|
345
|
+
|
346
|
+
Returns:
|
347
|
+
unsafe (bool): Проверка файла на безопасность максом
|
348
|
+
url (str): Ссылка на скачивание файла
|
349
|
+
"""
|
350
|
+
try:
|
351
|
+
self.logger.info(
|
352
|
+
"Getting file_id=%s message_id=%s", file_id, message_id
|
353
|
+
)
|
354
|
+
payload = GetFilePayload(
|
355
|
+
chat_id=chat_id,
|
356
|
+
message_id=message_id,
|
357
|
+
file_id=file_id
|
358
|
+
).model_dump(by_alias=True)
|
359
|
+
data = await self._send_and_wait(opcode=Opcode.FILE_DOWNLOAD, payload=payload)
|
360
|
+
if error := data.get("payload", {}).get("error"):
|
361
|
+
self.logger.error("Get file error: %s", error)
|
362
|
+
file = FileRequest.from_dict(data["payload"]) if data.get("payload") else None
|
363
|
+
self.logger.debug(" result: %r", file)
|
364
|
+
return file
|
365
|
+
except Exception:
|
366
|
+
self.logger.exception("Get video error")
|
367
|
+
return None
|
pymax/mixins/socket.py
CHANGED
@@ -214,9 +214,7 @@ Socket connections may be unstable, SSL issues are possible.
|
|
214
214
|
for handler, filter in self._on_message_handlers:
|
215
215
|
payload = data_item.get("payload", {})
|
216
216
|
msg_dict = (
|
217
|
-
payload
|
218
|
-
if isinstance(payload, dict)
|
219
|
-
else None
|
217
|
+
payload if isinstance(payload, dict) else None
|
220
218
|
)
|
221
219
|
msg = (
|
222
220
|
Message.from_dict(msg_dict)
|
pymax/mixins/websocket.py
CHANGED
@@ -118,7 +118,7 @@ class WebSocketMixin(ClientProtocol):
|
|
118
118
|
try:
|
119
119
|
for handler, filter in self._on_message_handlers:
|
120
120
|
payload = data.get("payload", {})
|
121
|
-
msg = Message.from_dict(payload
|
121
|
+
msg = Message.from_dict(payload)
|
122
122
|
if msg:
|
123
123
|
if msg.status:
|
124
124
|
continue # TODO: заглушка! сделать отдельный хендлер
|
pymax/payloads.py
CHANGED
@@ -193,3 +193,13 @@ class NavigationEventPayload(CamelModel):
|
|
193
193
|
|
194
194
|
class NavigationPayload(CamelModel):
|
195
195
|
events: list[NavigationEventPayload]
|
196
|
+
|
197
|
+
class GetVideoPayload(CamelModel):
|
198
|
+
chat_id: int
|
199
|
+
message_id: str
|
200
|
+
video_id: int
|
201
|
+
|
202
|
+
class GetFilePayload(CamelModel):
|
203
|
+
chat_id: int
|
204
|
+
message_id: str
|
205
|
+
file_id: int
|
pymax/types.py
CHANGED
@@ -167,6 +167,46 @@ class FileAttach:
|
|
167
167
|
return f"FileAttach: {self.file_id}"
|
168
168
|
|
169
169
|
|
170
|
+
class FileRequest:
|
171
|
+
def __init__(
|
172
|
+
self,
|
173
|
+
unsafe: bool,
|
174
|
+
url: str,
|
175
|
+
) -> None:
|
176
|
+
self.unsafe = unsafe
|
177
|
+
self.url = url
|
178
|
+
|
179
|
+
@classmethod
|
180
|
+
def from_dict(cls, data: dict[str, Any]) -> "FileRequest":
|
181
|
+
return cls(
|
182
|
+
unsafe=data["unsafe"],
|
183
|
+
url=data["url"],
|
184
|
+
)
|
185
|
+
|
186
|
+
|
187
|
+
class VideoRequest:
|
188
|
+
def __init__(
|
189
|
+
self,
|
190
|
+
external: str,
|
191
|
+
cache: bool,
|
192
|
+
url: str,
|
193
|
+
) -> None:
|
194
|
+
self.external = external
|
195
|
+
self.cache = cache
|
196
|
+
self.url = url
|
197
|
+
|
198
|
+
@classmethod
|
199
|
+
def from_dict(cls, data: dict[str, Any]) -> "VideoRequest":
|
200
|
+
|
201
|
+
listdata = list(data.values()) # Костыль ✅
|
202
|
+
|
203
|
+
return cls(
|
204
|
+
external=data["EXTERNAL"],
|
205
|
+
cache=data["cache"],
|
206
|
+
url=listdata[2],
|
207
|
+
)
|
208
|
+
|
209
|
+
|
170
210
|
class Me:
|
171
211
|
def __init__(
|
172
212
|
self,
|
@@ -230,6 +270,7 @@ class Element:
|
|
230
270
|
class Message:
|
231
271
|
def __init__(
|
232
272
|
self,
|
273
|
+
chat_id: int | None,
|
233
274
|
sender: int | None,
|
234
275
|
elements: list[Element] | None,
|
235
276
|
reaction_info: dict[str, Any] | None,
|
@@ -241,6 +282,7 @@ class Message:
|
|
241
282
|
type: MessageType | str,
|
242
283
|
attaches: list[PhotoAttach | VideoAttach | FileAttach],
|
243
284
|
) -> None:
|
285
|
+
self.chat_id = chat_id
|
244
286
|
self.sender = sender
|
245
287
|
self.elements = elements
|
246
288
|
self.options = options
|
@@ -254,8 +296,9 @@ class Message:
|
|
254
296
|
|
255
297
|
@classmethod
|
256
298
|
def from_dict(cls, data: dict[Any, Any]) -> "Message":
|
299
|
+
message = data["message"] if data.get("message") else data
|
257
300
|
attaches = []
|
258
|
-
for a in
|
301
|
+
for a in message.get("attaches", []):
|
259
302
|
if a["_type"] == AttachType.PHOTO:
|
260
303
|
attaches.append(PhotoAttach.from_dict(a))
|
261
304
|
elif a["_type"] == AttachType.VIDEO:
|
@@ -263,16 +306,17 @@ class Message:
|
|
263
306
|
elif a["_type"] == AttachType.FILE:
|
264
307
|
attaches.append(FileAttach.from_dict(a))
|
265
308
|
return cls(
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
309
|
+
chat_id=data.get("chatId"),
|
310
|
+
sender=message.get("sender"),
|
311
|
+
elements=[Element.from_dict(e) for e in message.get("elements", [])],
|
312
|
+
options=message.get("options"),
|
313
|
+
id=message["id"],
|
314
|
+
time=message["time"],
|
315
|
+
text=message["text"],
|
316
|
+
type=message["type"],
|
273
317
|
attaches=attaches,
|
274
|
-
status=
|
275
|
-
reaction_info=
|
318
|
+
status=message.get("status"),
|
319
|
+
reaction_info=message.get("reactionInfo"),
|
276
320
|
)
|
277
321
|
|
278
322
|
@override
|
@@ -280,6 +324,7 @@ class Message:
|
|
280
324
|
return (
|
281
325
|
f"Message(id={self.id!r}, sender={self.sender!r}, text={self.text!r}, "
|
282
326
|
f"type={self.type!r}, status={self.status!r}, elements={self.elements!r})"
|
327
|
+
f"attaches={self.attaches!r}, chat_id={self.chat_id!r}, time={self.time!r}, options={self.options!r}, reactionInfo={self.reactionInfo!r})"
|
283
328
|
)
|
284
329
|
|
285
330
|
@override
|
@@ -533,7 +578,7 @@ class User:
|
|
533
578
|
return f"User {self.id}: {', '.join(str(n) for n in self.names)}"
|
534
579
|
|
535
580
|
|
536
|
-
class Attach: # УБРАТЬ ГАДА!!!
|
581
|
+
class Attach: # УБРАТЬ ГАДА!!! или нет...
|
537
582
|
def __init__(
|
538
583
|
self,
|
539
584
|
_type: AttachType,
|
File without changes
|
File without changes
|