maxapi-python 1.1.12__tar.gz → 1.1.14__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.
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/.github/ISSUE_TEMPLATE/bug_report.md +3 -3
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/.github/workflows/publish.yml +1 -1
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/.gitignore +1 -1
- maxapi_python-1.1.14/.pre-commit-config.yaml +41 -0
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/LICENSE +1 -1
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/PKG-INFO +20 -20
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/README.md +15 -15
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/assets/icon.svg +0 -1
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/assets/logo.svg +0 -1
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/docs/assets/icon.svg +0 -1
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/docs/client.md +2 -2
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/docs/examples.md +11 -11
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/docs/index.md +2 -2
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/examples/example.py +24 -10
- maxapi_python-1.1.14/examples/telegram_bridge.py +202 -0
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/mkdocs.yml +1 -1
- maxapi_python-1.1.14/pyproject.toml +72 -0
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/ruff.toml +1 -1
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/src/pymax/__init__.py +8 -6
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/src/pymax/core.py +20 -48
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/src/pymax/crud.py +10 -9
- maxapi_python-1.1.14/src/pymax/exceptions.py +66 -0
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/src/pymax/files.py +13 -4
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/src/pymax/filters.py +8 -3
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/src/pymax/formatting.py +4 -4
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/src/pymax/interfaces.py +15 -15
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/src/pymax/mixins/auth.py +23 -5
- maxapi_python-1.1.14/src/pymax/mixins/channel.py +115 -0
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/src/pymax/mixins/group.py +30 -10
- maxapi_python-1.1.14/src/pymax/mixins/handler.py +114 -0
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/src/pymax/mixins/message.py +79 -32
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/src/pymax/mixins/self.py +4 -2
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/src/pymax/mixins/socket.py +169 -66
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/src/pymax/mixins/telemetry.py +11 -6
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/src/pymax/mixins/user.py +23 -1
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/src/pymax/mixins/websocket.py +112 -44
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/src/pymax/navigation.py +3 -1
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/src/pymax/payloads.py +39 -8
- maxapi_python-1.1.14/src/pymax/static/constant.py +26 -0
- maxapi_python-1.1.12/src/pymax/static.py → maxapi_python-1.1.14/src/pymax/static/enum.py +14 -35
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/src/pymax/types.py +310 -40
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/src/pymax/utils.py +11 -3
- maxapi_python-1.1.12/pyproject.toml +0 -50
- maxapi_python-1.1.12/scripts/build.py +0 -47
- maxapi_python-1.1.12/src/pymax/exceptions.py +0 -29
- maxapi_python-1.1.12/src/pymax/mixins/channel.py +0 -25
- maxapi_python-1.1.12/src/pymax/mixins/handler.py +0 -61
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/.github/FUNDING.yml +0 -0
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/.github/ISSUE_TEMPLATE/refactor.md +0 -0
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/.github/pull_request_template.md +0 -0
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/docs/api.md +0 -0
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/docs/methods.md +0 -0
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/docs/types.md +0 -0
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/src/pymax/mixins/__init__.py +0 -0
- {maxapi_python-1.1.12 → maxapi_python-1.1.14}/src/pymax/models.py +0 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
3
|
+
rev: v6.0.0
|
|
4
|
+
hooks:
|
|
5
|
+
- id: check-case-conflict
|
|
6
|
+
- id: check-docstring-first
|
|
7
|
+
- id: check-executables-have-shebangs
|
|
8
|
+
- id: check-shebang-scripts-are-executable
|
|
9
|
+
- id: check-yaml
|
|
10
|
+
- id: end-of-file-fixer
|
|
11
|
+
- id: fix-byte-order-marker
|
|
12
|
+
- id: mixed-line-ending
|
|
13
|
+
- id: name-tests-test
|
|
14
|
+
- id: trailing-whitespace
|
|
15
|
+
- repo: https://github.com/psf/black
|
|
16
|
+
rev: 25.9.0
|
|
17
|
+
hooks:
|
|
18
|
+
- id: black
|
|
19
|
+
- repo: https://github.com/csachs/pyproject-flake8
|
|
20
|
+
rev: v7.0.0
|
|
21
|
+
hooks:
|
|
22
|
+
- id: pyproject-flake8
|
|
23
|
+
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
24
|
+
rev: v1.18.2
|
|
25
|
+
hooks:
|
|
26
|
+
- id: mypy
|
|
27
|
+
additional_dependencies:
|
|
28
|
+
- "aiohttp"
|
|
29
|
+
- "sqlalchemy"
|
|
30
|
+
- "sqlmodel"
|
|
31
|
+
- "types-aiofiles"
|
|
32
|
+
- "types-requests"
|
|
33
|
+
exclude: "^examples/"
|
|
34
|
+
- repo: https://github.com/pycqa/isort
|
|
35
|
+
rev: 7.0.0
|
|
36
|
+
hooks:
|
|
37
|
+
- id: isort
|
|
38
|
+
- repo: https://github.com/PyCQA/bandit
|
|
39
|
+
rev: 1.8.6
|
|
40
|
+
hooks:
|
|
41
|
+
- id: bandit
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: maxapi-python
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.14
|
|
4
4
|
Summary: Python wrapper для API мессенджера Max
|
|
5
|
-
Project-URL: Homepage, https://github.com/
|
|
6
|
-
Project-URL: Repository, https://github.com/
|
|
7
|
-
Project-URL: Issues, https://github.com/
|
|
8
|
-
Author-email:
|
|
5
|
+
Project-URL: Homepage, https://github.com/ink-developer/PyMax
|
|
6
|
+
Project-URL: Repository, https://github.com/ink-developer/PyMax
|
|
7
|
+
Project-URL: Issues, https://github.com/ink-developer/PyMax/issues
|
|
8
|
+
Author-email: ink <mail@gmail.com>
|
|
9
9
|
License-Expression: MIT
|
|
10
10
|
License-File: LICENSE
|
|
11
11
|
Keywords: api,max,messenger,websocket,wrapper
|
|
@@ -37,7 +37,7 @@ Description-Content-Type: text/markdown
|
|
|
37
37
|
|
|
38
38
|
---
|
|
39
39
|
> ⚠️ **Дисклеймер**
|
|
40
|
-
>
|
|
40
|
+
>
|
|
41
41
|
> * Это **неофициальная** библиотека для работы с внутренним API Max.
|
|
42
42
|
> * Использование может **нарушать условия предоставления услуг** сервиса.
|
|
43
43
|
> * **Вы используете её исключительно на свой страх и риск.**
|
|
@@ -94,7 +94,7 @@ async def handle_message(message: Message) -> None:
|
|
|
94
94
|
@client.on_start
|
|
95
95
|
async def handle_start() -> None:
|
|
96
96
|
print("Клиент запущен")
|
|
97
|
-
|
|
97
|
+
|
|
98
98
|
# Получение истории сообщений
|
|
99
99
|
history = await client.fetch_history(chat_id=0)
|
|
100
100
|
if history:
|
|
@@ -105,38 +105,38 @@ async def handle_start() -> None:
|
|
|
105
105
|
|
|
106
106
|
async def main() -> None:
|
|
107
107
|
await client.start()
|
|
108
|
-
|
|
108
|
+
|
|
109
109
|
# Работа с чатами
|
|
110
110
|
for chat in client.chats:
|
|
111
111
|
print(f"Чат: {chat.title}")
|
|
112
|
-
|
|
112
|
+
|
|
113
113
|
# Отправка сообщения
|
|
114
114
|
message = await client.send_message(
|
|
115
|
-
"Привет от PyMax!",
|
|
116
|
-
chat.id,
|
|
115
|
+
"Привет от PyMax!",
|
|
116
|
+
chat.id,
|
|
117
117
|
notify=True
|
|
118
118
|
)
|
|
119
|
-
|
|
119
|
+
|
|
120
120
|
# Редактирование сообщения
|
|
121
121
|
await asyncio.sleep(2)
|
|
122
122
|
await client.edit_message(
|
|
123
|
-
chat.id,
|
|
124
|
-
message.id,
|
|
123
|
+
chat.id,
|
|
124
|
+
message.id,
|
|
125
125
|
"Привет от PyMax! (отредактировано)"
|
|
126
126
|
)
|
|
127
|
-
|
|
127
|
+
|
|
128
128
|
# Удаление сообщения
|
|
129
129
|
await asyncio.sleep(2)
|
|
130
130
|
await client.delete_message(chat.id, [message.id], for_me=False)
|
|
131
|
-
|
|
131
|
+
|
|
132
132
|
# Работа с диалогами
|
|
133
133
|
for dialog in client.dialogs:
|
|
134
134
|
print(f"Диалог: {dialog.last_message.text}")
|
|
135
|
-
|
|
135
|
+
|
|
136
136
|
# Работа с каналами
|
|
137
137
|
for channel in client.channels:
|
|
138
138
|
print(f"Канал: {channel.title}")
|
|
139
|
-
|
|
139
|
+
|
|
140
140
|
await client.close()
|
|
141
141
|
|
|
142
142
|
if __name__ == "__main__":
|
|
@@ -145,7 +145,7 @@ if __name__ == "__main__":
|
|
|
145
145
|
|
|
146
146
|
## Документация
|
|
147
147
|
|
|
148
|
-
[WIP](https://
|
|
148
|
+
[WIP](https://ink-developer.github.io/)
|
|
149
149
|
|
|
150
150
|
## Лицензия
|
|
151
151
|
|
|
@@ -157,7 +157,7 @@ if __name__ == "__main__":
|
|
|
157
157
|
|
|
158
158
|
## Авторы
|
|
159
159
|
|
|
160
|
-
- **[
|
|
160
|
+
- **[ink-developer](https://github.com/ink-developer)** — Оригинальный автор проекта
|
|
161
161
|
- **[ink](https://github.com/ink-developer)** — Главный разработчик, исследование API и его документация
|
|
162
162
|
|
|
163
163
|
## Контрибьюторы
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
> ⚠️ **Дисклеймер**
|
|
18
|
-
>
|
|
18
|
+
>
|
|
19
19
|
> * Это **неофициальная** библиотека для работы с внутренним API Max.
|
|
20
20
|
> * Использование может **нарушать условия предоставления услуг** сервиса.
|
|
21
21
|
> * **Вы используете её исключительно на свой страх и риск.**
|
|
@@ -72,7 +72,7 @@ async def handle_message(message: Message) -> None:
|
|
|
72
72
|
@client.on_start
|
|
73
73
|
async def handle_start() -> None:
|
|
74
74
|
print("Клиент запущен")
|
|
75
|
-
|
|
75
|
+
|
|
76
76
|
# Получение истории сообщений
|
|
77
77
|
history = await client.fetch_history(chat_id=0)
|
|
78
78
|
if history:
|
|
@@ -83,38 +83,38 @@ async def handle_start() -> None:
|
|
|
83
83
|
|
|
84
84
|
async def main() -> None:
|
|
85
85
|
await client.start()
|
|
86
|
-
|
|
86
|
+
|
|
87
87
|
# Работа с чатами
|
|
88
88
|
for chat in client.chats:
|
|
89
89
|
print(f"Чат: {chat.title}")
|
|
90
|
-
|
|
90
|
+
|
|
91
91
|
# Отправка сообщения
|
|
92
92
|
message = await client.send_message(
|
|
93
|
-
"Привет от PyMax!",
|
|
94
|
-
chat.id,
|
|
93
|
+
"Привет от PyMax!",
|
|
94
|
+
chat.id,
|
|
95
95
|
notify=True
|
|
96
96
|
)
|
|
97
|
-
|
|
97
|
+
|
|
98
98
|
# Редактирование сообщения
|
|
99
99
|
await asyncio.sleep(2)
|
|
100
100
|
await client.edit_message(
|
|
101
|
-
chat.id,
|
|
102
|
-
message.id,
|
|
101
|
+
chat.id,
|
|
102
|
+
message.id,
|
|
103
103
|
"Привет от PyMax! (отредактировано)"
|
|
104
104
|
)
|
|
105
|
-
|
|
105
|
+
|
|
106
106
|
# Удаление сообщения
|
|
107
107
|
await asyncio.sleep(2)
|
|
108
108
|
await client.delete_message(chat.id, [message.id], for_me=False)
|
|
109
|
-
|
|
109
|
+
|
|
110
110
|
# Работа с диалогами
|
|
111
111
|
for dialog in client.dialogs:
|
|
112
112
|
print(f"Диалог: {dialog.last_message.text}")
|
|
113
|
-
|
|
113
|
+
|
|
114
114
|
# Работа с каналами
|
|
115
115
|
for channel in client.channels:
|
|
116
116
|
print(f"Канал: {channel.title}")
|
|
117
|
-
|
|
117
|
+
|
|
118
118
|
await client.close()
|
|
119
119
|
|
|
120
120
|
if __name__ == "__main__":
|
|
@@ -123,7 +123,7 @@ if __name__ == "__main__":
|
|
|
123
123
|
|
|
124
124
|
## Документация
|
|
125
125
|
|
|
126
|
-
[WIP](https://
|
|
126
|
+
[WIP](https://ink-developer.github.io/)
|
|
127
127
|
|
|
128
128
|
## Лицензия
|
|
129
129
|
|
|
@@ -135,7 +135,7 @@ if __name__ == "__main__":
|
|
|
135
135
|
|
|
136
136
|
## Авторы
|
|
137
137
|
|
|
138
|
-
- **[
|
|
138
|
+
- **[ink-developer](https://github.com/ink-developer)** — Оригинальный автор проекта
|
|
139
139
|
- **[ink](https://github.com/ink-developer)** — Главный разработчик, исследование API и его документация
|
|
140
140
|
|
|
141
141
|
## Контрибьюторы
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
client = MaxClient(
|
|
20
20
|
phone: str,
|
|
21
21
|
uri: str = Constants.WEBSOCKET_URI.value,
|
|
22
|
-
headers: dict[str, Any] | None = Constants.
|
|
22
|
+
headers: dict[str, Any] | None = Constants.DEFAULT_USER_AGENT_PAYLOAD.value,
|
|
23
23
|
token: str | None = None,
|
|
24
24
|
send_fake_telemetry: bool = True,
|
|
25
25
|
host: str = Constants.HOST.value,
|
|
@@ -35,7 +35,7 @@ client = MaxClient(
|
|
|
35
35
|
|----------|-----|----------|---------------|
|
|
36
36
|
| `phone` | `str` | Номер телефона для авторизации | - |
|
|
37
37
|
| `uri` | `str` | URI WebSocket сервера | `Constants.WEBSOCKET_URI.value` |
|
|
38
|
-
| `headers` | `dict[str, Any] \| None` | Заголовки для соединения | `Constants.
|
|
38
|
+
| `headers` | `dict[str, Any] \| None` | Заголовки для соединения | `Constants.DEFAULT_USER_AGENT_PAYLOAD.value` |
|
|
39
39
|
| `token` | `str \| None` | Токен авторизации | `None` |
|
|
40
40
|
| `send_fake_telemetry` | `bool` | Отправка телеметрии | `True` |
|
|
41
41
|
| `host` | `str` | Хост API сервера | `Constants.HOST.value` |
|
|
@@ -8,14 +8,14 @@ from pymax import MaxClient
|
|
|
8
8
|
|
|
9
9
|
async def main():
|
|
10
10
|
client = MaxClient(phone="+79001234567")
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
@client.on_message
|
|
13
13
|
async def echo_handler(message):
|
|
14
14
|
await client.send_message(
|
|
15
15
|
chat_id=message.chat_id,
|
|
16
16
|
text=f"Эхо: {message.text}"
|
|
17
17
|
)
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
await client.start()
|
|
20
20
|
|
|
21
21
|
asyncio.run(main())
|
|
@@ -29,7 +29,7 @@ from pymax import MaxClient
|
|
|
29
29
|
|
|
30
30
|
async def main():
|
|
31
31
|
client = MaxClient(phone="+79001234567")
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
# Словарь ключевых слов и ответов
|
|
34
34
|
auto_replies = {
|
|
35
35
|
'привет': 'Привет! Как дела?',
|
|
@@ -37,11 +37,11 @@ async def main():
|
|
|
37
37
|
'спасибо': 'Пожалуйста!',
|
|
38
38
|
'время': 'Время ответить на ваш вопрос!',
|
|
39
39
|
}
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
@client.on_message
|
|
42
42
|
async def auto_reply_handler(message):
|
|
43
43
|
text = message.text.lower()
|
|
44
|
-
|
|
44
|
+
|
|
45
45
|
for keyword, reply in auto_replies.items():
|
|
46
46
|
if keyword in text:
|
|
47
47
|
await client.send_message(
|
|
@@ -49,7 +49,7 @@ async def main():
|
|
|
49
49
|
text=reply
|
|
50
50
|
)
|
|
51
51
|
break
|
|
52
|
-
|
|
52
|
+
|
|
53
53
|
await client.start()
|
|
54
54
|
|
|
55
55
|
asyncio.run(main())
|
|
@@ -63,14 +63,14 @@ from pymax import MaxClient
|
|
|
63
63
|
|
|
64
64
|
async def main():
|
|
65
65
|
client = MaxClient(phone="+79001234567")
|
|
66
|
-
|
|
66
|
+
|
|
67
67
|
# Запрещенные слова
|
|
68
68
|
forbidden_words = ['спам', 'реклама', 'взлом']
|
|
69
|
-
|
|
69
|
+
|
|
70
70
|
@client.on_message
|
|
71
71
|
async def moderation_handler(message):
|
|
72
72
|
text = message.text.lower()
|
|
73
|
-
|
|
73
|
+
|
|
74
74
|
for word in forbidden_words:
|
|
75
75
|
if word in text:
|
|
76
76
|
# Удаляем сообщение
|
|
@@ -78,14 +78,14 @@ async def main():
|
|
|
78
78
|
chat_id=message.chat_id,
|
|
79
79
|
message_id=message.id
|
|
80
80
|
)
|
|
81
|
-
|
|
81
|
+
|
|
82
82
|
# Предупреждаем пользователя
|
|
83
83
|
await client.send_message(
|
|
84
84
|
chat_id=message.chat_id,
|
|
85
85
|
text=f"@{message.author.username}, использование запрещенных слов недопустимо!"
|
|
86
86
|
)
|
|
87
87
|
break
|
|
88
|
-
|
|
88
|
+
|
|
89
89
|
await client.start()
|
|
90
90
|
|
|
91
91
|
asyncio.run(main())
|
|
@@ -39,6 +39,6 @@ uv add -U maxapi-python
|
|
|
39
39
|
|
|
40
40
|
## Ссылки
|
|
41
41
|
|
|
42
|
-
- [GitHub](https://github.com/
|
|
42
|
+
- [GitHub](https://github.com/ink-developer/PyMax)
|
|
43
43
|
- [PyPI](https://pypi.org/project/pymax/)
|
|
44
|
-
- [Issues](https://github.com/
|
|
44
|
+
- [Issues](https://github.com/ink-developer/PyMax/issues)
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
import logging
|
|
3
2
|
|
|
4
|
-
from pymax import MaxClient, Message
|
|
5
|
-
from pymax.files import Photo
|
|
3
|
+
from pymax import MaxClient, Message
|
|
6
4
|
from pymax.filters import Filter
|
|
7
|
-
from pymax.static import AttachType
|
|
5
|
+
from pymax.static.enum import AttachType
|
|
8
6
|
|
|
9
7
|
phone = "+1234567890"
|
|
10
8
|
|
|
11
9
|
|
|
12
10
|
client = MaxClient(phone=phone, work_dir="cache")
|
|
13
|
-
# client = SocketMaxClient(phone=phone, work_dir="cache")
|
|
14
11
|
|
|
15
12
|
|
|
16
13
|
@client.on_message(filter=Filter(chat_id=0))
|
|
@@ -18,9 +15,26 @@ async def handle_message(message: Message) -> None:
|
|
|
18
15
|
print(str(message.sender) + ": " + message.text)
|
|
19
16
|
|
|
20
17
|
|
|
18
|
+
@client.on_message_edit()
|
|
19
|
+
async def handle_edited_message(message: Message) -> None:
|
|
20
|
+
print(f"Edited message in chat {message.chat_id}: {message.text}")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@client.on_message_delete()
|
|
24
|
+
async def handle_deleted_message(message: Message) -> None:
|
|
25
|
+
print(f"Deleted message in chat {message.chat_id}: {message.id}")
|
|
26
|
+
|
|
27
|
+
|
|
21
28
|
@client.on_start
|
|
22
29
|
async def handle_start() -> None:
|
|
23
30
|
print("Client started successfully!")
|
|
31
|
+
history = await client.fetch_history(chat_id=0)
|
|
32
|
+
if history:
|
|
33
|
+
for message in history:
|
|
34
|
+
if message.attaches:
|
|
35
|
+
for attach in message.attaches:
|
|
36
|
+
if attach.type == AttachType.STICKER:
|
|
37
|
+
print(attach.lottie_url)
|
|
24
38
|
# chat = await client.rework_invite_link(chat_id=0)
|
|
25
39
|
# print(chat.link)
|
|
26
40
|
# text = """
|
|
@@ -78,12 +92,12 @@ async def handle_start() -> None:
|
|
|
78
92
|
# print(client.me.names[0].first_name)
|
|
79
93
|
# user = await client.get_user(client.me.id)
|
|
80
94
|
|
|
81
|
-
photo1 = Photo(path="tests/test.jpeg")
|
|
82
|
-
photo2 = Photo(path="tests/test.jpg")
|
|
95
|
+
# photo1 = Photo(path="tests/test.jpeg")
|
|
96
|
+
# photo2 = Photo(path="tests/test.jpg")
|
|
83
97
|
|
|
84
|
-
await client.send_message(
|
|
85
|
-
|
|
86
|
-
)
|
|
98
|
+
# await client.send_message(
|
|
99
|
+
# "Hello with photo!", chat_id=0, photos=[photo1, photo2], notify=True
|
|
100
|
+
# )
|
|
87
101
|
|
|
88
102
|
|
|
89
103
|
if __name__ == "__main__":
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import os
|
|
3
|
+
from io import BytesIO
|
|
4
|
+
|
|
5
|
+
import aiohttp
|
|
6
|
+
from aiogram import Bot, Dispatcher, types
|
|
7
|
+
from dotenv import load_dotenv
|
|
8
|
+
|
|
9
|
+
from pymax import Chat, MaxClient, Message, User
|
|
10
|
+
from pymax.types import FileAttach, PhotoAttach, VideoAttach
|
|
11
|
+
|
|
12
|
+
"""
|
|
13
|
+
Зависимости:
|
|
14
|
+
|
|
15
|
+
pip install maxapi-python==1.1.13 aiogram==3.22.0 python-dotenv
|
|
16
|
+
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
"""
|
|
21
|
+
В .env нужно указать:
|
|
22
|
+
|
|
23
|
+
PHONE = "+7123456789" # Твой номер для Max
|
|
24
|
+
BOT_TOKEN = "23456789:AAH0cJ3SNzZ2zzD0uF8HOqmxtKpwsKwggM" # Твой токен Telegram-бота
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
chats = { # В формате айди чата в Max: айди чата в Telegram
|
|
29
|
+
-68690734055662: -1003177746657,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# Создаём зеркальный массив для отправки из Telegram в Max
|
|
34
|
+
chats_telegram = {value: key for key, value in chats.items()}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# Загружаем .env
|
|
38
|
+
load_dotenv(override=True)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# Настройки из .env
|
|
42
|
+
PHONE = os.getenv("PHONE") # Номер телефона Max
|
|
43
|
+
telegram_bot_TOKEN = os.getenv("BOT_TOKEN") # Токен TG-бота
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
client = MaxClient(phone=PHONE, work_dir="cache")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# Инициализация TG-бота
|
|
50
|
+
telegram_bot = Bot(token=telegram_bot_TOKEN)
|
|
51
|
+
dp = Dispatcher()
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# Обработчик входящих сообщений MAX
|
|
55
|
+
@client.on_message()
|
|
56
|
+
async def handle_message(message: Message) -> None:
|
|
57
|
+
tg_id = chats[message.chat_id]
|
|
58
|
+
|
|
59
|
+
sender = await client.get_user(user_id=message.sender)
|
|
60
|
+
|
|
61
|
+
if message.attaches:
|
|
62
|
+
for attach in message.attaches:
|
|
63
|
+
# Проверка на видео
|
|
64
|
+
if isinstance(attach, VideoAttach):
|
|
65
|
+
async with aiohttp.ClientSession() as session:
|
|
66
|
+
try:
|
|
67
|
+
# Получаем видео по айди
|
|
68
|
+
video = await client.get_video_by_id(
|
|
69
|
+
chat_id=message.chat_id,
|
|
70
|
+
message_id=message.id,
|
|
71
|
+
video_id=attach.video_id,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
# Загружаем видео по URL
|
|
75
|
+
async with session.get(video.url) as response:
|
|
76
|
+
response.raise_for_status() # Проверка на ошибки HTTP
|
|
77
|
+
video_bytes = BytesIO(await response.read())
|
|
78
|
+
video_bytes.name = response.headers.get("X-File-Name")
|
|
79
|
+
|
|
80
|
+
# Отправляем видео через телеграм бота
|
|
81
|
+
await telegram_bot.send_video(
|
|
82
|
+
chat_id=tg_id,
|
|
83
|
+
caption=f"{sender.names[0].name}: {message.text}",
|
|
84
|
+
video=types.BufferedInputFile(
|
|
85
|
+
video_bytes.getvalue(), filename=video_bytes.name
|
|
86
|
+
),
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
# Очищаем память
|
|
90
|
+
video_bytes.close()
|
|
91
|
+
|
|
92
|
+
except aiohttp.ClientError as e:
|
|
93
|
+
print(f"Ошибка при загрузке видео: {e}")
|
|
94
|
+
except Exception as e:
|
|
95
|
+
print(f"Ошибка при отправке видео: {e}")
|
|
96
|
+
|
|
97
|
+
# Проверка на изображение
|
|
98
|
+
elif isinstance(attach, PhotoAttach):
|
|
99
|
+
async with aiohttp.ClientSession() as session:
|
|
100
|
+
try:
|
|
101
|
+
# Загружаем изображение по URL
|
|
102
|
+
async with session.get(attach.base_url) as response:
|
|
103
|
+
response.raise_for_status() # Проверка на ошибки HTTP
|
|
104
|
+
photo_bytes = BytesIO(await response.read())
|
|
105
|
+
photo_bytes.name = response.headers.get("X-File-Name")
|
|
106
|
+
|
|
107
|
+
# Отправляем фото через телеграм бота
|
|
108
|
+
await telegram_bot.send_photo(
|
|
109
|
+
chat_id=tg_id,
|
|
110
|
+
caption=f"{sender.names[0].name}: {message.text}",
|
|
111
|
+
photo=types.BufferedInputFile(
|
|
112
|
+
photo_bytes.getvalue(), filename=photo_bytes.name
|
|
113
|
+
),
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
# Очищаем память
|
|
117
|
+
photo_bytes.close()
|
|
118
|
+
|
|
119
|
+
except aiohttp.ClientError as e:
|
|
120
|
+
print(f"Ошибка при загрузке изображения: {e}")
|
|
121
|
+
except Exception as e:
|
|
122
|
+
print(f"Ошибка при отправке фото: {e}")
|
|
123
|
+
|
|
124
|
+
# Проверка на файл
|
|
125
|
+
elif isinstance(attach, FileAttach):
|
|
126
|
+
async with aiohttp.ClientSession() as session:
|
|
127
|
+
try:
|
|
128
|
+
# Получаем файл по айди
|
|
129
|
+
file = await client.get_file_by_id(
|
|
130
|
+
chat_id=message.chat_id,
|
|
131
|
+
message_id=message.id,
|
|
132
|
+
file_id=attach.file_id,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
# Загружаем файл по URL
|
|
136
|
+
async with session.get(file.url) as response:
|
|
137
|
+
response.raise_for_status() # Проверка на ошибки HTTP
|
|
138
|
+
file_bytes = BytesIO(await response.read())
|
|
139
|
+
file_bytes.name = response.headers.get("X-File-Name")
|
|
140
|
+
|
|
141
|
+
# Отправляем файл через телеграм бота
|
|
142
|
+
await telegram_bot.send_document(
|
|
143
|
+
chat_id=tg_id,
|
|
144
|
+
caption=f"{sender.names[0].name}: {message.text}",
|
|
145
|
+
document=types.BufferedInputFile(
|
|
146
|
+
file_bytes.getvalue(), filename=file_bytes.name
|
|
147
|
+
),
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
# Очищаем память
|
|
151
|
+
file_bytes.close()
|
|
152
|
+
|
|
153
|
+
except aiohttp.ClientError as e:
|
|
154
|
+
print(f"Ошибка при загрузке файла: {e}")
|
|
155
|
+
except Exception as e:
|
|
156
|
+
print(f"Ошибка при отправке файла: {e}")
|
|
157
|
+
else:
|
|
158
|
+
await telegram_bot.send_message(
|
|
159
|
+
chat_id=tg_id, text=f"{sender.names[0].name}: {message.text}"
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
# Обработчик запуска клиента, функция выводит все сообщения из чата "Избранное"
|
|
164
|
+
@client.on_start
|
|
165
|
+
async def handle_start() -> None:
|
|
166
|
+
print("Клиент запущен")
|
|
167
|
+
|
|
168
|
+
# Получение истории сообщений
|
|
169
|
+
history = await client.fetch_history(chat_id=0)
|
|
170
|
+
if history:
|
|
171
|
+
for message in history:
|
|
172
|
+
user = await client.get_user(message.sender)
|
|
173
|
+
if user:
|
|
174
|
+
print(f"{user.names[0].name}: {message.text}")
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
# Обработчик сообщений Telegram
|
|
178
|
+
@dp.message()
|
|
179
|
+
async def handle_message(message: types.Message, bot: Bot) -> None:
|
|
180
|
+
max_id = chats_telegram[message.chat.id]
|
|
181
|
+
await client.send_message(chat_id=max_id, text=message.text, notify=True)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
# Раннер ботов
|
|
185
|
+
async def main() -> None:
|
|
186
|
+
# TG-бот в фоне
|
|
187
|
+
telegram_bot_task = asyncio.create_task(dp.start_polling(telegram_bot))
|
|
188
|
+
|
|
189
|
+
try:
|
|
190
|
+
while True: # Не спрашивайте 😃
|
|
191
|
+
await client.start()
|
|
192
|
+
|
|
193
|
+
finally:
|
|
194
|
+
await client.close()
|
|
195
|
+
telegram_bot_task.cancel()
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
if __name__ == "__main__":
|
|
199
|
+
try:
|
|
200
|
+
asyncio.run(main())
|
|
201
|
+
except KeyboardInterrupt:
|
|
202
|
+
print("Программа остановлена пользователем.")
|
|
@@ -150,6 +150,6 @@ markdown_extensions:
|
|
|
150
150
|
extra:
|
|
151
151
|
social:
|
|
152
152
|
- icon: fontawesome/brands/github
|
|
153
|
-
link: https://github.com/
|
|
153
|
+
link: https://github.com/ink-developer/PyMax
|
|
154
154
|
- icon: fontawesome/brands/python
|
|
155
155
|
link: https://pypi.org/project/maxapi-python
|