maxapi-python 1.1.4__tar.gz → 1.1.5__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.
Files changed (41) hide show
  1. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/.gitignore +4 -0
  2. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/PKG-INFO +2 -2
  3. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/examples/example.py +16 -8
  4. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/pyproject.toml +2 -2
  5. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/src/pymax/mixins/message.py +83 -1
  6. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/src/pymax/payloads.py +10 -0
  7. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/src/pymax/types.py +41 -1
  8. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/.github/FUNDING.yml +0 -0
  9. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/.github/workflows/publish.yml +0 -0
  10. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/LICENSE +0 -0
  11. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/README.md +0 -0
  12. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/assets/icon.svg +0 -0
  13. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/assets/logo.svg +0 -0
  14. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/docs/api.md +0 -0
  15. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/docs/assets/icon.svg +0 -0
  16. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/docs/examples.md +0 -0
  17. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/docs/index.md +0 -0
  18. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/mkdocs.yml +0 -0
  19. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/ruff.toml +0 -0
  20. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/scripts/build.py +0 -0
  21. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/src/pymax/__init__.py +0 -0
  22. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/src/pymax/core.py +0 -0
  23. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/src/pymax/crud.py +0 -0
  24. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/src/pymax/exceptions.py +0 -0
  25. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/src/pymax/files.py +0 -0
  26. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/src/pymax/filters.py +0 -0
  27. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/src/pymax/interfaces.py +0 -0
  28. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/src/pymax/mixins/__init__.py +0 -0
  29. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/src/pymax/mixins/auth.py +0 -0
  30. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/src/pymax/mixins/channel.py +0 -0
  31. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/src/pymax/mixins/group.py +0 -0
  32. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/src/pymax/mixins/handler.py +0 -0
  33. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/src/pymax/mixins/self.py +0 -0
  34. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/src/pymax/mixins/socket.py +0 -0
  35. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/src/pymax/mixins/telemetry.py +0 -0
  36. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/src/pymax/mixins/user.py +0 -0
  37. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/src/pymax/mixins/websocket.py +0 -0
  38. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/src/pymax/models.py +0 -0
  39. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/src/pymax/navigation.py +0 -0
  40. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/src/pymax/static.py +0 -0
  41. {maxapi_python-1.1.4 → maxapi_python-1.1.5}/src/pymax/utils.py +0 -0
@@ -115,3 +115,7 @@ cache/
115
115
  # Keep lockfiles and important configs tracked? If you want to track specific lockfiles,
116
116
  # remove them from this .gitignore (for example: remove poetry.lock or uv.lock).
117
117
  tests/
118
+
119
+
120
+ # Bad dev's requirements
121
+ requirements.txt
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maxapi-python
3
- Version: 1.1.4
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>=11.0
20
+ Requires-Dist: websockets>=15.0
21
21
  Description-Content-Type: text/markdown
22
22
 
23
23
  <p align="center">
@@ -49,14 +49,22 @@ async def handle_start() -> None:
49
49
  history = await client.fetch_history(chat_id=0)
50
50
  if history:
51
51
  for message in history:
52
- user_id = message.sender
53
- chat_id = message.chat_id
54
- print(chat_id)
55
- user = await client.get_user(user_id)
56
-
57
- if user:
58
- print(f"{user.names[0].name}: {message.text}")
59
-
52
+ if message.attaches:
53
+ for attach in message.attaches:
54
+ if attach.type == AttachType.VIDEO:
55
+ vid = await client.get_video_by_id(
56
+ chat_id=0,
57
+ video_id=attach.video_id,
58
+ message_id=message.id,
59
+ )
60
+ print(vid.url)
61
+ elif attach.type == AttachType.FILE:
62
+ file = await client.get_file_by_id(
63
+ chat_id=0,
64
+ file_id=attach.file_id,
65
+ message_id=message.id,
66
+ )
67
+ print(file.url)
60
68
  # print(client.me.names[0].first_name)
61
69
  # user = await client.get_user(client.me.id)
62
70
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "maxapi-python"
3
- version = "1.1.4"
3
+ version = "1.1.5"
4
4
  description = "Python wrapper для API мессенджера Max"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -16,7 +16,7 @@ classifiers = [
16
16
  ]
17
17
  dependencies = [
18
18
  "sqlmodel>=0.0.24",
19
- "websockets>=11.0",
19
+ "websockets>=15.0",
20
20
  "msgpack>=1.1.1",
21
21
  "lz4>=4.4.4",
22
22
  "aiohttp>=3.12.15",
@@ -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):
@@ -283,3 +285,83 @@ class MessageMixin(ClientProtocol):
283
285
  except Exception:
284
286
  self.logger.exception("Fetch history failed")
285
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
@@ -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
@@ -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,
@@ -538,7 +578,7 @@ class User:
538
578
  return f"User {self.id}: {', '.join(str(n) for n in self.names)}"
539
579
 
540
580
 
541
- class Attach: # УБРАТЬ ГАДА!!!
581
+ class Attach: # УБРАТЬ ГАДА!!! или нет...
542
582
  def __init__(
543
583
  self,
544
584
  _type: AttachType,
File without changes
File without changes
File without changes
File without changes
File without changes