maxapi-python 1.1.5__tar.gz → 1.1.8__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 (46) hide show
  1. maxapi_python-1.1.8/.github/ISSUE_TEMPLATE/bug_report.md +25 -0
  2. maxapi_python-1.1.8/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
  3. maxapi_python-1.1.8/.github/ISSUE_TEMPLATE/refactor.md +25 -0
  4. maxapi_python-1.1.8/.github/pull_request_template.md +19 -0
  5. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/PKG-INFO +10 -4
  6. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/README.md +9 -3
  7. maxapi_python-1.1.8/examples/example.py +62 -0
  8. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/pyproject.toml +1 -1
  9. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/src/pymax/files.py +1 -1
  10. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/src/pymax/mixins/message.py +39 -29
  11. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/src/pymax/mixins/user.py +36 -1
  12. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/src/pymax/payloads.py +8 -2
  13. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/src/pymax/static.py +1 -0
  14. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/src/pymax/types.py +37 -8
  15. maxapi_python-1.1.5/examples/example.py +0 -82
  16. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/.github/FUNDING.yml +0 -0
  17. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/.github/workflows/publish.yml +0 -0
  18. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/.gitignore +0 -0
  19. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/LICENSE +0 -0
  20. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/assets/icon.svg +0 -0
  21. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/assets/logo.svg +0 -0
  22. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/docs/api.md +0 -0
  23. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/docs/assets/icon.svg +0 -0
  24. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/docs/examples.md +0 -0
  25. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/docs/index.md +0 -0
  26. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/mkdocs.yml +0 -0
  27. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/ruff.toml +0 -0
  28. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/scripts/build.py +0 -0
  29. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/src/pymax/__init__.py +0 -0
  30. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/src/pymax/core.py +0 -0
  31. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/src/pymax/crud.py +0 -0
  32. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/src/pymax/exceptions.py +0 -0
  33. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/src/pymax/filters.py +0 -0
  34. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/src/pymax/interfaces.py +0 -0
  35. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/src/pymax/mixins/__init__.py +0 -0
  36. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/src/pymax/mixins/auth.py +0 -0
  37. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/src/pymax/mixins/channel.py +0 -0
  38. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/src/pymax/mixins/group.py +0 -0
  39. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/src/pymax/mixins/handler.py +0 -0
  40. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/src/pymax/mixins/self.py +0 -0
  41. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/src/pymax/mixins/socket.py +0 -0
  42. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/src/pymax/mixins/telemetry.py +0 -0
  43. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/src/pymax/mixins/websocket.py +0 -0
  44. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/src/pymax/models.py +0 -0
  45. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/src/pymax/navigation.py +0 -0
  46. {maxapi_python-1.1.5 → maxapi_python-1.1.8}/src/pymax/utils.py +0 -0
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: Bug report
3
+ about: Сообщить о баге
4
+ title: ''
5
+ labels: bug
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ **Описание**
11
+ Что пошло не так?
12
+
13
+ **Шаги для воспроизведения**
14
+ 1.
15
+ 2.
16
+ 3.
17
+
18
+ **Ожидаемый результат**
19
+ Что должно было произойти
20
+
21
+ **Фактический результат**
22
+ Что произошло на самом деле
23
+
24
+ **Дополнительно**
25
+ Логи, скриншоты, версия Python/API
@@ -0,0 +1,19 @@
1
+ ---
2
+ name: Feature Request
3
+ about: Предложить новую функциональность
4
+ title: ''
5
+ labels: enhancement
6
+ assignees: ''
7
+ ---
8
+
9
+ **Описание**
10
+ Опишите новую функцию или улучшение.
11
+
12
+ **Зачем это нужно**
13
+ Кратко объясните, какую проблему решает или что улучшает.
14
+
15
+ **Пример использования**
16
+ Как это будет использоваться в коде:
17
+
18
+ ```python
19
+ # пример
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: Refactor
3
+ about: Предложение по улучшению кода без изменения функционала
4
+ title: ''
5
+ labels: refactor
6
+ assignees: ''
7
+ ---
8
+
9
+ ## Описание
10
+ Опишите часть кода, которую нужно улучшить или рефакторить, без изменения функциональности.
11
+
12
+ ## Причина
13
+ Почему требуется рефакторинг? Например:
14
+ - Улучшение читаемости кода
15
+ - Повышение производительности
16
+ - Упрощение поддержки
17
+
18
+ ## Предлагаемые изменения
19
+ Опишите, как вы планируете изменить код, чтобы улучшить его структуру или качество.
20
+
21
+ ## Влияние
22
+ Какие модули/части библиотеки могут быть затронуты? Нужно убедиться, что функционал остаётся прежним.
23
+
24
+ ## Дополнительно
25
+ Любая дополнительная информация, ссылки на документацию, примеры кода.
@@ -0,0 +1,19 @@
1
+ ## Описание
2
+ Кратко, что делает этот PR. Например, добавляет новый метод, исправляет баг, улучшает документацию.
3
+
4
+ ## Тип изменений
5
+ - [ ] Исправление бага
6
+ - [ ] Новая функциональность
7
+ - [ ] Улучшение документации
8
+ - [ ] Рефакторинг
9
+
10
+ ## Связанные задачи / Issue
11
+ Ссылка на issue, если есть: #
12
+
13
+ ## Тестирование
14
+ Покажите пример кода, который проверяет изменения:
15
+
16
+ ```python
17
+ import pymax
18
+
19
+ # пример использования нового функционала
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maxapi-python
3
- Version: 1.1.5
3
+ Version: 1.1.8
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
@@ -157,7 +157,13 @@ if __name__ == "__main__":
157
157
 
158
158
  ## Авторы
159
159
 
160
- - **[noxzion](https://github.com/noxzion)** — оригинальный автор проекта
161
- - **[ink](https://github.com/ink-developer)** — второй разработчик, исследование API и его документация
162
- - **[fresh-milkshake](https://github.com/fresh-milkshake)** — контрибьютор и автор лого
160
+ - **[noxzion](https://github.com/noxzion)** — Оригинальный автор проекта
161
+ - **[ink](https://github.com/ink-developer)** — Главный разработчик, исследование API и его документация
163
162
 
163
+ ## Контрибьюторы
164
+
165
+ Спасибо всем за помощь в разработке!
166
+
167
+ <a href="https://github.com/ink-developer/PyMax/graphs/contributors">
168
+ <img src="https://contrib.rocks/image?repo=ink-developer/PyMax" />
169
+ </a>
@@ -135,7 +135,13 @@ if __name__ == "__main__":
135
135
 
136
136
  ## Авторы
137
137
 
138
- - **[noxzion](https://github.com/noxzion)** — оригинальный автор проекта
139
- - **[ink](https://github.com/ink-developer)** — второй разработчик, исследование API и его документация
140
- - **[fresh-milkshake](https://github.com/fresh-milkshake)** — контрибьютор и автор лого
138
+ - **[noxzion](https://github.com/noxzion)** — Оригинальный автор проекта
139
+ - **[ink](https://github.com/ink-developer)** — Главный разработчик, исследование API и его документация
141
140
 
141
+ ## Контрибьюторы
142
+
143
+ Спасибо всем за помощь в разработке!
144
+
145
+ <a href="https://github.com/ink-developer/PyMax/graphs/contributors">
146
+ <img src="https://contrib.rocks/image?repo=ink-developer/PyMax" />
147
+ </a>
@@ -0,0 +1,62 @@
1
+ import asyncio
2
+ import logging
3
+
4
+ from pymax import MaxClient, Message, SocketMaxClient
5
+ from pymax.files import Photo
6
+ from pymax.filters import Filter
7
+ from pymax.static import AttachType
8
+
9
+ phone = "+1234567890"
10
+
11
+
12
+ client = MaxClient(phone=phone, work_dir="cache")
13
+ # client = SocketMaxClient(phone=phone, work_dir="cache")
14
+
15
+
16
+ @client.on_message(filter=Filter(chat_id=0))
17
+ async def handle_message(message: Message) -> None:
18
+ print(str(message.sender) + ": " + message.text)
19
+
20
+
21
+ @client.on_start
22
+ async def handle_start() -> None:
23
+ print("Client started successfully!")
24
+ # print(client.dialogs)
25
+ history = await client.fetch_history(chat_id=0)
26
+ if history:
27
+ for message in history:
28
+ if message.attaches:
29
+ for attach in message.attaches:
30
+ if attach.type == AttachType.CONTROL:
31
+ print(attach.event)
32
+ print(attach.extra)
33
+ # if attach.type == AttachType.VIDEO:
34
+ # print(message)
35
+ # vid = await client.get_video_by_id(
36
+ # chat_id=0,
37
+ # video_id=attach.video_id,
38
+ # message_id=message.id,
39
+ # )
40
+ # print(vid.url)
41
+ # elif attach.type == AttachType.FILE:
42
+ # file = await client.get_file_by_id(
43
+ # chat_id=0,
44
+ # file_id=attach.file_id,
45
+ # message_id=message.id,
46
+ # )
47
+ # print(file.url)
48
+ # print(client.me.names[0].first_name)
49
+ # user = await client.get_user(client.me.id)
50
+
51
+ # print(user.names[0].first_name)
52
+
53
+ # photo1 = Photo(path="tests/test.jpeg")
54
+ # photo2 = Photo(path="tests/test.jpg")
55
+
56
+ # await client.send_message(
57
+ # "Hello with photo!", chat_id=0, photos=[photo1, photo2], notify=True
58
+ # )
59
+
60
+
61
+ if __name__ == "__main__":
62
+ asyncio.run(client.start())
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "maxapi-python"
3
- version = "1.1.5"
3
+ version = "1.1.8"
4
4
  description = "Python wrapper для API мессенджера Max"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -56,7 +56,7 @@ class Photo(BaseFile):
56
56
  return (extension[1:], ("image/" + extension[1:]).lower())
57
57
  elif self.url:
58
58
  extension = Path(self.url).suffix.lower()
59
- if extension in self.ALLOWED_EXTENSIONS:
59
+ if extension not in self.ALLOWED_EXTENSIONS:
60
60
  raise ValueError(
61
61
  f"Invalid photo extension in URL: {extension}. Allowed: {self.ALLOWED_EXTENSIONS}"
62
62
  )
@@ -10,16 +10,16 @@ from pymax.payloads import (
10
10
  DeleteMessagePayload,
11
11
  EditMessagePayload,
12
12
  FetchHistoryPayload,
13
+ GetFilePayload,
14
+ GetVideoPayload,
13
15
  PinMessagePayload,
14
16
  ReplyLink,
15
17
  SendMessagePayload,
16
18
  SendMessagePayloadMessage,
17
19
  UploadPhotoPayload,
18
- GetVideoPayload,
19
- GetFilePayload,
20
20
  )
21
21
  from pymax.static import AttachType, Opcode
22
- from pymax.types import Attach, Message, FileRequest, VideoRequest
22
+ from pymax.types import Attach, FileRequest, Message, VideoRequest
23
23
 
24
24
 
25
25
  class MessageMixin(ClientProtocol):
@@ -143,7 +143,6 @@ class MessageMixin(ClientProtocol):
143
143
  data = await self._send_and_wait(opcode=Opcode.MSG_SEND, payload=payload)
144
144
  if error := data.get("payload", {}).get("error"):
145
145
  self.logger.error("Send message error: %s", error)
146
- print(data)
147
146
  return None
148
147
  msg = Message.from_dict(data["payload"]) if data.get("payload") else None
149
148
  self.logger.debug("send_message result: %r", msg)
@@ -286,12 +285,11 @@ class MessageMixin(ClientProtocol):
286
285
  self.logger.exception("Fetch history failed")
287
286
  return None
288
287
 
289
-
290
288
  async def get_video_by_id(
291
289
  self,
292
290
  chat_id: int,
293
291
  message_id: int,
294
- video_id: str,
292
+ video_id: int,
295
293
  ) -> VideoRequest | None:
296
294
  """
297
295
  Получает видео
@@ -307,33 +305,37 @@ class MessageMixin(ClientProtocol):
307
305
  url (str): Ссылка на видео
308
306
  """
309
307
  try:
310
- self.logger.info(
311
- "Getting video_id=%s message_id=%s", video_id, message_id
312
- )
308
+ self.logger.info("Getting video_id=%s message_id=%s", video_id, message_id)
313
309
 
314
- payload = GetVideoPayload(
315
- chat_id=chat_id,
316
- message_id=message_id,
317
- video_id=video_id
318
- ).model_dump(by_alias=True)
310
+ if self.is_connected and self._socket is not None:
311
+ payload = GetVideoPayload(
312
+ chat_id=chat_id, message_id=message_id, video_id=video_id
313
+ ).model_dump(by_alias=True)
314
+ else:
315
+ payload = GetVideoPayload(
316
+ chat_id=chat_id, message_id=str(message_id), video_id=video_id
317
+ ).model_dump(by_alias=True)
319
318
 
320
319
  data = await self._send_and_wait(opcode=Opcode.VIDEO_PLAY, payload=payload)
321
320
 
322
321
  if error := data.get("payload", {}).get("error"):
323
322
  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)
323
+ return
324
+
325
+ video = (
326
+ VideoRequest.from_dict(data["payload"]) if data.get("payload") else None
327
+ )
328
+ self.logger.debug("result: %r", video)
327
329
  return video
328
330
  except Exception:
329
331
  self.logger.exception("Get video error")
330
332
  return None
331
-
333
+
332
334
  async def get_file_by_id(
333
335
  self,
334
336
  chat_id: int,
335
337
  message_id: int,
336
- file_id: str,
338
+ file_id: int,
337
339
  ) -> FileRequest | None:
338
340
  """
339
341
  Получает файл
@@ -348,20 +350,28 @@ class MessageMixin(ClientProtocol):
348
350
  url (str): Ссылка на скачивание файла
349
351
  """
350
352
  try:
351
- self.logger.info(
352
- "Getting file_id=%s message_id=%s", file_id, message_id
353
+ self.logger.info("Getting file_id=%s message_id=%s", file_id, message_id)
354
+ if self.is_connected and self._socket is not None:
355
+ payload = GetFilePayload(
356
+ chat_id=chat_id, message_id=message_id, file_id=file_id
357
+ ).model_dump(by_alias=True)
358
+ else:
359
+ payload = GetFilePayload(
360
+ chat_id=chat_id, message_id=str(message_id), file_id=file_id
361
+ ).model_dump(by_alias=True)
362
+ data = await self._send_and_wait(
363
+ opcode=Opcode.FILE_DOWNLOAD, payload=payload
353
364
  )
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)
365
+
360
366
  if error := data.get("payload", {}).get("error"):
361
367
  self.logger.error("Get file error: %s", error)
362
- file = FileRequest.from_dict(data["payload"]) if data.get("payload") else None
368
+ return
369
+
370
+ file = (
371
+ FileRequest.from_dict(data["payload"]) if data.get("payload") else None
372
+ )
363
373
  self.logger.debug(" result: %r", file)
364
374
  return file
365
375
  except Exception:
366
376
  self.logger.exception("Get video error")
367
- return None
377
+ return None
@@ -1,5 +1,5 @@
1
1
  from pymax.interfaces import ClientProtocol
2
- from pymax.payloads import FetchContactsPayload
2
+ from pymax.payloads import FetchContactsPayload, SearchByPhonePayload
3
3
  from pymax.static import Opcode
4
4
  from pymax.types import User
5
5
 
@@ -80,3 +80,38 @@ class UserMixin(ClientProtocol):
80
80
  except Exception:
81
81
  self.logger.exception("Fetch users failed")
82
82
  return []
83
+
84
+ async def search_by_phone(self, phone: str) -> User | None:
85
+ """
86
+ Ищет пользователя по номеру телефона.
87
+
88
+ Args:
89
+ phone (str): Номер телефона.
90
+
91
+ Returns:
92
+ User | None: Объект User или None при ошибке.
93
+ """
94
+ try:
95
+ self.logger.info("Searching user by phone: %s", phone)
96
+
97
+ payload = SearchByPhonePayload(phone=phone).model_dump(by_alias=True)
98
+
99
+ data = await self._send_and_wait(
100
+ opcode=Opcode.CONTACT_INFO_BY_PHONE, payload=payload
101
+ )
102
+ if error := data.get("payload", {}).get("error"):
103
+ self.logger.error("Search by phone error: %s", error)
104
+ return None
105
+
106
+ user = (
107
+ User.from_dict(data["payload"]["contact"])
108
+ if data.get("payload")
109
+ else None
110
+ )
111
+ if user:
112
+ self._users[user.id] = user
113
+ self.logger.debug("Found user by phone: %s", user)
114
+ return user
115
+ except Exception:
116
+ self.logger.exception("Search by phone failed")
117
+ return None
@@ -194,12 +194,18 @@ class NavigationEventPayload(CamelModel):
194
194
  class NavigationPayload(CamelModel):
195
195
  events: list[NavigationEventPayload]
196
196
 
197
+
197
198
  class GetVideoPayload(CamelModel):
198
199
  chat_id: int
199
- message_id: str
200
+ message_id: int | str
200
201
  video_id: int
201
202
 
203
+
202
204
  class GetFilePayload(CamelModel):
203
205
  chat_id: int
204
- message_id: str
206
+ message_id: str | int
205
207
  file_id: int
208
+
209
+
210
+ class SearchByPhonePayload(CamelModel):
211
+ phone: str
@@ -191,6 +191,7 @@ class AttachType(str, Enum):
191
191
  VIDEO = "VIDEO"
192
192
  FILE = "FILE"
193
193
  STICKER = "STICKER"
194
+ CONTROL = "CONTROL"
194
195
 
195
196
 
196
197
  class Constants(Enum):
@@ -39,6 +39,32 @@ class Names:
39
39
  return self.name
40
40
 
41
41
 
42
+ class ControlAttach:
43
+ def __init__(self, type: AttachType, event: str, **kwargs: dict[str, Any]) -> None:
44
+ self.type = type
45
+ self.event = event
46
+ self.extra = kwargs
47
+
48
+ @classmethod
49
+ def from_dict(cls, data: dict[str, Any]) -> "ControlAttach":
50
+ data = dict(data)
51
+ attach_type = AttachType(data.pop("_type"))
52
+ event = data.pop("event")
53
+ return cls(
54
+ type=attach_type,
55
+ event=event,
56
+ **data,
57
+ )
58
+
59
+ @override
60
+ def __repr__(self) -> str:
61
+ return f"ControlAttach(type={self.type!r}, event={self.event!r}, extra={self.extra!r})"
62
+
63
+ @override
64
+ def __str__(self) -> str:
65
+ return f"ControlAttach: {self.event}"
66
+
67
+
42
68
  class PhotoAttach:
43
69
  def __init__(
44
70
  self,
@@ -181,7 +207,7 @@ class FileRequest:
181
207
  return cls(
182
208
  unsafe=data["unsafe"],
183
209
  url=data["url"],
184
- )
210
+ )
185
211
 
186
212
 
187
213
  class VideoRequest:
@@ -197,15 +223,16 @@ class VideoRequest:
197
223
 
198
224
  @classmethod
199
225
  def from_dict(cls, data: dict[str, Any]) -> "VideoRequest":
200
-
201
- listdata = list(data.values()) # Костыль
202
-
226
+ # listdata = list(data.values()) # Костыль ✅
227
+ url = [v for k, v in data.items() if k not in ("EXTERNAL", "cache")][
228
+ 0
229
+ ] # Еще больший костыль ✅
203
230
  return cls(
204
231
  external=data["EXTERNAL"],
205
232
  cache=data["cache"],
206
- url=listdata[2],
207
- )
208
-
233
+ url=url,
234
+ )
235
+
209
236
 
210
237
  class Me:
211
238
  def __init__(
@@ -280,7 +307,7 @@ class Message:
280
307
  text: str,
281
308
  status: MessageStatus | str | None,
282
309
  type: MessageType | str,
283
- attaches: list[PhotoAttach | VideoAttach | FileAttach],
310
+ attaches: list[PhotoAttach | VideoAttach | FileAttach | ControlAttach] | None,
284
311
  ) -> None:
285
312
  self.chat_id = chat_id
286
313
  self.sender = sender
@@ -305,6 +332,8 @@ class Message:
305
332
  attaches.append(VideoAttach.from_dict(a))
306
333
  elif a["_type"] == AttachType.FILE:
307
334
  attaches.append(FileAttach.from_dict(a))
335
+ elif a["_type"] == AttachType.CONTROL:
336
+ attaches.append(ControlAttach.from_dict(a))
308
337
  return cls(
309
338
  chat_id=data.get("chatId"),
310
339
  sender=message.get("sender"),
@@ -1,82 +0,0 @@
1
- import asyncio
2
- import logging
3
-
4
- from pymax import MaxClient, Message, SocketMaxClient
5
- from pymax.files import Photo
6
- from pymax.filters import Filter
7
- from pymax.static import AttachType
8
-
9
- phone = "+1234567890"
10
-
11
-
12
- client = MaxClient(phone=phone, work_dir="cache")
13
- # client = SocketMaxClient(phone=phone, work_dir="cache")
14
-
15
-
16
- async def main() -> None:
17
- for chat in client.chats:
18
- print(chat.title)
19
-
20
- message = await client.send_message(
21
- "Hello from MaxClient!", chat.id, notify=True
22
- )
23
-
24
- await asyncio.sleep(5)
25
- message = await client.edit_message(
26
- chat.id, message.id, "Hello from MaxClient! (edited)"
27
- )
28
- await asyncio.sleep(5)
29
-
30
- await client.delete_message(chat.id, [message.id], for_me=False)
31
-
32
- for dialog in client.dialogs:
33
- print(dialog.last_message.text)
34
-
35
- for channel in client.channels:
36
- print(channel.title)
37
-
38
- await client.close()
39
-
40
-
41
- @client.on_message(filter=Filter(chat_id=0))
42
- async def handle_message(message: Message) -> None:
43
- print(str(message.sender) + ": " + message.text)
44
-
45
-
46
- @client.on_start
47
- async def handle_start() -> None:
48
- print("Client started successfully!")
49
- history = await client.fetch_history(chat_id=0)
50
- if history:
51
- for message in history:
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)
68
- # print(client.me.names[0].first_name)
69
- # user = await client.get_user(client.me.id)
70
-
71
- # print(user.names[0].first_name)
72
-
73
- # photo1 = Photo(path="tests/test.jpeg")
74
- # photo2 = Photo(path="tests/test.jpg")
75
-
76
- # await client.send_message(
77
- # "Hello with photo!", chat_id=0, photos=[photo1, photo2], notify=True
78
- # )
79
-
80
-
81
- if __name__ == "__main__":
82
- asyncio.run(client.start())
File without changes
File without changes
File without changes
File without changes
File without changes