maxapi-python 0.1.1__py3-none-any.whl → 0.1.2__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-0.1.1.dist-info → maxapi_python-0.1.2.dist-info}/METADATA +20 -4
- maxapi_python-0.1.2.dist-info/RECORD +25 -0
- pymax/__init__.py +55 -0
- pymax/core.py +156 -0
- pymax/crud.py +99 -0
- pymax/exceptions.py +20 -0
- pymax/files.py +85 -0
- pymax/filters.py +38 -0
- pymax/interfaces.py +67 -0
- pymax/mixins/__init__.py +18 -0
- pymax/mixins/auth.py +81 -0
- pymax/mixins/channel.py +25 -0
- pymax/mixins/group.py +220 -0
- pymax/mixins/handler.py +60 -0
- pymax/mixins/message.py +293 -0
- pymax/mixins/self.py +38 -0
- pymax/mixins/user.py +82 -0
- pymax/mixins/websocket.py +242 -0
- pymax/models.py +8 -0
- pymax/payloads.py +175 -0
- pymax/static.py +210 -0
- pymax/types.py +432 -0
- pymax/utils.py +38 -0
- maxapi_python-0.1.1.dist-info/RECORD +0 -4
- {maxapi_python-0.1.1.dist-info → maxapi_python-0.1.2.dist-info}/WHEEL +0 -0
- {maxapi_python-0.1.1.dist-info → maxapi_python-0.1.2.dist-info}/licenses/LICENSE +0 -0
pymax/static.py
ADDED
@@ -0,0 +1,210 @@
|
|
1
|
+
from enum import Enum, IntEnum
|
2
|
+
|
3
|
+
|
4
|
+
class Opcode(IntEnum):
|
5
|
+
PING = 1
|
6
|
+
DEBUG = 2
|
7
|
+
RECONNECT = 3
|
8
|
+
LOG = 5
|
9
|
+
SESSION_INIT = 6
|
10
|
+
PROFILE = 16
|
11
|
+
AUTH_REQUEST = 17
|
12
|
+
AUTH = 18
|
13
|
+
LOGIN = 19
|
14
|
+
LOGOUT = 20
|
15
|
+
SYNC = 21
|
16
|
+
CONFIG = 22
|
17
|
+
AUTH_CONFIRM = 23
|
18
|
+
PRESET_AVATARS = 25
|
19
|
+
ASSETS_GET = 26
|
20
|
+
UNKNOWN_26 = 26
|
21
|
+
ASSETS_UPDATE = 27
|
22
|
+
ASSETS_GET_BY_IDS = 28
|
23
|
+
ASSETS_ADD = 29
|
24
|
+
SEARCH_FEEDBACK = 31
|
25
|
+
CONTACT_INFO = 32
|
26
|
+
CONTACT_ADD = 33
|
27
|
+
CONTACT_UPDATE = 34
|
28
|
+
CONTACT_PRESENCE = 35
|
29
|
+
CONTACT_LIST = 36
|
30
|
+
CONTACT_SEARCH = 37
|
31
|
+
CONTACT_MUTUAL = 38
|
32
|
+
CONTACT_PHOTOS = 39
|
33
|
+
CONTACT_SORT = 40
|
34
|
+
CONTACT_VERIFY = 42
|
35
|
+
REMOVE_CONTACT_PHOTO = 43
|
36
|
+
CONTACT_INFO_BY_PHONE = 46
|
37
|
+
CHAT_INFO = 48
|
38
|
+
CHAT_HISTORY = 49
|
39
|
+
CHAT_MARK = 50
|
40
|
+
CHAT_MEDIA = 51
|
41
|
+
CHAT_DELETE = 52
|
42
|
+
CHATS_LIST = 53
|
43
|
+
CHAT_CLEAR = 54
|
44
|
+
CHAT_UPDATE = 55
|
45
|
+
CHAT_CHECK_LINK = 56
|
46
|
+
CHAT_JOIN = 57
|
47
|
+
CHAT_LEAVE = 58
|
48
|
+
CHAT_MEMBERS = 59
|
49
|
+
PUBLIC_SEARCH = 60
|
50
|
+
CHAT_CLOSE = 61
|
51
|
+
CHAT_CREATE = 63
|
52
|
+
MSG_SEND = 64
|
53
|
+
MSG_TYPING = 65
|
54
|
+
MSG_DELETE = 66
|
55
|
+
MSG_EDIT = 67
|
56
|
+
CHAT_SEARCH = 68
|
57
|
+
MSG_SHARE_PREVIEW = 70
|
58
|
+
MSG_GET = 71
|
59
|
+
MSG_SEARCH_TOUCH = 72
|
60
|
+
MSG_SEARCH = 73
|
61
|
+
MSG_GET_STAT = 74
|
62
|
+
CHAT_SUBSCRIBE = 75
|
63
|
+
VIDEO_CHAT_START = 76
|
64
|
+
CHAT_MEMBERS_UPDATE = 77
|
65
|
+
VIDEO_CHAT_HISTORY = 79
|
66
|
+
PHOTO_UPLOAD = 80
|
67
|
+
STICKER_UPLOAD = 81
|
68
|
+
VIDEO_UPLOAD = 82
|
69
|
+
VIDEO_PLAY = 83
|
70
|
+
CHAT_PIN_SET_VISIBILITY = 86
|
71
|
+
FILE_UPLOAD = 87
|
72
|
+
FILE_DOWNLOAD = 88
|
73
|
+
LINK_INFO = 89
|
74
|
+
MSG_DELETE_RANGE = 92
|
75
|
+
SESSIONS_INFO = 96
|
76
|
+
SESSIONS_CLOSE = 97
|
77
|
+
PHONE_BIND_REQUEST = 98
|
78
|
+
PHONE_BIND_CONFIRM = 99
|
79
|
+
CONFIRM_PRESENT = 101
|
80
|
+
GET_INBOUND_CALLS = 103
|
81
|
+
EXTERNAL_CALLBACK = 105
|
82
|
+
AUTH_VALIDATE_PASSWORD = 107
|
83
|
+
AUTH_VALIDATE_HINT = 108
|
84
|
+
AUTH_VERIFY_EMAIL = 109
|
85
|
+
AUTH_CHECK_EMAIL = 110
|
86
|
+
AUTH_SET_2FA = 111
|
87
|
+
AUTH_CREATE_TRACK = 112
|
88
|
+
AUTH_LOGIN_CHECK_PASSWORD = 115
|
89
|
+
CHAT_COMPLAIN = 117
|
90
|
+
MSG_SEND_CALLBACK = 118
|
91
|
+
SUSPEND_BOT = 119
|
92
|
+
LOCATION_STOP = 124
|
93
|
+
LOCATION_SEND = 125
|
94
|
+
LOCATION_REQUEST = 126
|
95
|
+
GET_LAST_MENTIONS = 127
|
96
|
+
NOTIF_MESSAGE = 128
|
97
|
+
NOTIF_TYPING = 129
|
98
|
+
NOTIF_MARK = 130
|
99
|
+
NOTIF_CONTACT = 131
|
100
|
+
NOTIF_PRESENCE = 132
|
101
|
+
NOTIF_CONFIG = 134
|
102
|
+
NOTIF_CHAT = 135
|
103
|
+
NOTIF_ATTACH = 136
|
104
|
+
NOTIF_CALL_START = 137
|
105
|
+
NOTIF_CONTACT_SORT = 139
|
106
|
+
NOTIF_MSG_DELETE_RANGE = 140
|
107
|
+
NOTIF_MSG_DELETE = 142
|
108
|
+
NOTIF_CALLBACK_ANSWER = 143
|
109
|
+
CHAT_BOT_COMMANDS = 144
|
110
|
+
BOT_INFO = 145
|
111
|
+
NOTIF_LOCATION = 147
|
112
|
+
NOTIF_LOCATION_REQUEST = 148
|
113
|
+
NOTIF_ASSETS_UPDATE = 150
|
114
|
+
NOTIF_DRAFT = 152
|
115
|
+
NOTIF_DRAFT_DISCARD = 153
|
116
|
+
NOTIF_MSG_DELAYED = 154
|
117
|
+
NOTIF_MSG_REACTIONS_CHANGED = 155
|
118
|
+
NOTIF_MSG_YOU_REACTED = 156
|
119
|
+
CALLS_TOKEN = 158
|
120
|
+
NOTIF_PROFILE = 159
|
121
|
+
WEB_APP_INIT_DATA = 160
|
122
|
+
DRAFT_SAVE = 176
|
123
|
+
DRAFT_DISCARD = 177
|
124
|
+
MSG_REACTION = 178
|
125
|
+
MSG_CANCEL_REACTION = 179
|
126
|
+
MSG_GET_REACTIONS = 180
|
127
|
+
MSG_GET_DETAILED_REACTIONS = 181
|
128
|
+
STICKER_CREATE = 193
|
129
|
+
STICKER_SUGGEST = 194
|
130
|
+
VIDEO_CHAT_MEMBERS = 195
|
131
|
+
CHAT_HIDE = 196
|
132
|
+
CHAT_SEARCH_COMMON_PARTICIPANTS = 198
|
133
|
+
PROFILE_DELETE = 199
|
134
|
+
PROFILE_DELETE_TIME = 200
|
135
|
+
ASSETS_REMOVE = 259
|
136
|
+
ASSETS_MOVE = 260
|
137
|
+
ASSETS_LIST_MODIFY = 261
|
138
|
+
FOLDERS_GET = 272
|
139
|
+
FOLDERS_GET_BY_ID = 273
|
140
|
+
FOLDERS_UPDATE = 274
|
141
|
+
FOLDERS_REORDER = 275
|
142
|
+
FOLDERS_DELETE = 276
|
143
|
+
NOTIF_FOLDERS = 277
|
144
|
+
|
145
|
+
|
146
|
+
class ChatType(str, Enum):
|
147
|
+
DIALOG = "DIALOG"
|
148
|
+
CHAT = "CHAT"
|
149
|
+
CHANNEL = "CHANNEL"
|
150
|
+
|
151
|
+
|
152
|
+
class MessageType(str, Enum):
|
153
|
+
TEXT = "TEXT"
|
154
|
+
SYSTEM = "SYSTEM"
|
155
|
+
SERVICE = "SERVICE"
|
156
|
+
|
157
|
+
|
158
|
+
class MessageStatus(str, Enum):
|
159
|
+
SENT = "SENT"
|
160
|
+
DELIVERED = "DELIVERED"
|
161
|
+
READ = "READ"
|
162
|
+
ERROR = "ERROR"
|
163
|
+
|
164
|
+
|
165
|
+
class ElementType(str, Enum):
|
166
|
+
TEXT = "text"
|
167
|
+
MENTION = "mention"
|
168
|
+
LINK = "link"
|
169
|
+
EMOJI = "emoji"
|
170
|
+
|
171
|
+
|
172
|
+
class AuthType(str, Enum):
|
173
|
+
START_AUTH = "START_AUTH"
|
174
|
+
CHECK_CODE = "CHECK_CODE"
|
175
|
+
|
176
|
+
|
177
|
+
class AccessType(str, Enum):
|
178
|
+
PUBLIC = "PUBLIC"
|
179
|
+
PRIVATE = "PRIVATE"
|
180
|
+
SECRET = "SECRET"
|
181
|
+
|
182
|
+
|
183
|
+
class DeviceType(str, Enum):
|
184
|
+
WEB = "WEB"
|
185
|
+
ANDROID = "ANDROID"
|
186
|
+
IOS = "IOS"
|
187
|
+
|
188
|
+
|
189
|
+
class AttachType(str, Enum):
|
190
|
+
PHOTO = "PHOTO"
|
191
|
+
VIDEO = "VIDEO"
|
192
|
+
FILE = "FILE"
|
193
|
+
STICKER = "STICKER"
|
194
|
+
|
195
|
+
|
196
|
+
class Constants(Enum):
|
197
|
+
PHONE_REGEX = r"^\+?\d{10,15}$"
|
198
|
+
WEBSOCKET_URI = "wss://ws-api.oneme.ru/websocket"
|
199
|
+
DEFAULT_TIMEOUT = 10.0
|
200
|
+
DEFAULT_USER_AGENT = {
|
201
|
+
"deviceType": "WEB",
|
202
|
+
"locale": "ru",
|
203
|
+
"deviceLocale": "ru",
|
204
|
+
"osVersion": "Linux",
|
205
|
+
"deviceName": "Chrome",
|
206
|
+
"headerUserAgent": "Mozilla/5.0 ...",
|
207
|
+
"appVersion": "25.8.5",
|
208
|
+
"screen": "1080x1920 1.0x",
|
209
|
+
"timezone": "Europe/Moscow",
|
210
|
+
}
|
pymax/types.py
ADDED
@@ -0,0 +1,432 @@
|
|
1
|
+
from typing import Any, override
|
2
|
+
|
3
|
+
from .static import (
|
4
|
+
AccessType,
|
5
|
+
AttachType,
|
6
|
+
ChatType,
|
7
|
+
ElementType,
|
8
|
+
MessageStatus,
|
9
|
+
MessageType,
|
10
|
+
)
|
11
|
+
|
12
|
+
|
13
|
+
class Names:
|
14
|
+
def __init__(
|
15
|
+
self, name: str, first_name: str, last_name: str | None, type: str
|
16
|
+
) -> None:
|
17
|
+
self.name = name
|
18
|
+
self.first_name = first_name
|
19
|
+
self.last_name = last_name
|
20
|
+
self.type = type
|
21
|
+
|
22
|
+
@classmethod
|
23
|
+
def from_dict(cls, data: dict[str, Any]) -> "Names":
|
24
|
+
return cls(
|
25
|
+
name=data["name"],
|
26
|
+
first_name=data["firstName"],
|
27
|
+
last_name=data.get("lastName"),
|
28
|
+
type=data["type"],
|
29
|
+
)
|
30
|
+
|
31
|
+
@override
|
32
|
+
def __repr__(self) -> str:
|
33
|
+
return f"Names(name={self.name!r}, first_name={self.first_name!r}, last_name={self.last_name!r}, type={self.type!r})"
|
34
|
+
|
35
|
+
@override
|
36
|
+
def __str__(self) -> str:
|
37
|
+
return self.name
|
38
|
+
|
39
|
+
|
40
|
+
class Me:
|
41
|
+
def __init__(
|
42
|
+
self,
|
43
|
+
id: int,
|
44
|
+
account_status: int,
|
45
|
+
phone: str,
|
46
|
+
names: list[Names],
|
47
|
+
update_time: int,
|
48
|
+
options: list[str] | None = None,
|
49
|
+
) -> None:
|
50
|
+
self.id = id
|
51
|
+
self.account_status = account_status
|
52
|
+
self.phone = phone
|
53
|
+
self.update_time = update_time
|
54
|
+
self.options = options
|
55
|
+
self.names = names
|
56
|
+
|
57
|
+
@classmethod
|
58
|
+
def from_dict(cls, data: dict[str, Any]) -> "Me":
|
59
|
+
return cls(
|
60
|
+
id=data["id"],
|
61
|
+
account_status=data["accountStatus"],
|
62
|
+
phone=data["phone"],
|
63
|
+
names=[Names.from_dict(n) for n in data["names"]],
|
64
|
+
update_time=data["updateTime"],
|
65
|
+
options=data.get("options"),
|
66
|
+
)
|
67
|
+
|
68
|
+
@override
|
69
|
+
def __repr__(self) -> str:
|
70
|
+
return f"Me(id={self.id!r}, account_status={self.account_status!r}, phone={self.phone!r}, names={self.names!r}, update_time={self.update_time!r}, options={self.options!r})"
|
71
|
+
|
72
|
+
@override
|
73
|
+
def __str__(self) -> str:
|
74
|
+
return f"Me {self.id}: {', '.join(str(n) for n in self.names)}"
|
75
|
+
|
76
|
+
|
77
|
+
class Element:
|
78
|
+
def __init__(
|
79
|
+
self, type: ElementType | str, length: int, from_: int | None = None
|
80
|
+
) -> None:
|
81
|
+
self.type = type
|
82
|
+
self.length = length
|
83
|
+
self.from_ = from_
|
84
|
+
|
85
|
+
@classmethod
|
86
|
+
def from_dict(cls, data: dict[Any, Any]) -> "Element":
|
87
|
+
return cls(type=data["type"], length=data["length"], from_=data.get("from"))
|
88
|
+
|
89
|
+
@override
|
90
|
+
def __repr__(self) -> str:
|
91
|
+
return (
|
92
|
+
f"Element(type={self.type!r}, length={self.length!r}, from_={self.from_!r})"
|
93
|
+
)
|
94
|
+
|
95
|
+
@override
|
96
|
+
def __str__(self) -> str:
|
97
|
+
return f"{self.type}({self.length})"
|
98
|
+
|
99
|
+
|
100
|
+
class Message:
|
101
|
+
def __init__(
|
102
|
+
self,
|
103
|
+
sender: int | None,
|
104
|
+
elements: list[Element] | None,
|
105
|
+
reaction_info: dict[str, Any] | None,
|
106
|
+
options: int | None,
|
107
|
+
id: int,
|
108
|
+
time: int,
|
109
|
+
text: str,
|
110
|
+
status: MessageStatus | str | None,
|
111
|
+
type: MessageType | str,
|
112
|
+
attaches: list[Any],
|
113
|
+
) -> None:
|
114
|
+
self.sender = sender
|
115
|
+
self.elements = elements
|
116
|
+
self.options = options
|
117
|
+
self.id = id
|
118
|
+
self.time = time
|
119
|
+
self.text = text
|
120
|
+
self.type = type
|
121
|
+
self.attaches = attaches
|
122
|
+
self.status = status
|
123
|
+
self.reactionInfo = reaction_info
|
124
|
+
|
125
|
+
@classmethod
|
126
|
+
def from_dict(cls, data: dict[Any, Any]) -> "Message":
|
127
|
+
return cls(
|
128
|
+
sender=data.get("sender"),
|
129
|
+
elements=[Element.from_dict(e) for e in data.get("elements", [])],
|
130
|
+
options=data.get("options"),
|
131
|
+
id=data["id"],
|
132
|
+
time=data["time"],
|
133
|
+
text=data["text"],
|
134
|
+
type=data["type"],
|
135
|
+
attaches=data.get("attaches", []),
|
136
|
+
status=data.get("status"),
|
137
|
+
reaction_info=data.get("reactionInfo"),
|
138
|
+
)
|
139
|
+
|
140
|
+
@override
|
141
|
+
def __repr__(self) -> str:
|
142
|
+
return (
|
143
|
+
f"Message(id={self.id!r}, sender={self.sender!r}, text={self.text!r}, "
|
144
|
+
f"type={self.type!r}, status={self.status!r}, elements={self.elements!r})"
|
145
|
+
)
|
146
|
+
|
147
|
+
@override
|
148
|
+
def __str__(self) -> str:
|
149
|
+
return f"Message {self.id} from {self.sender}: {self.text}"
|
150
|
+
|
151
|
+
|
152
|
+
class Dialog:
|
153
|
+
def __init__(
|
154
|
+
self,
|
155
|
+
cid: int | None,
|
156
|
+
owner: int,
|
157
|
+
has_bots: bool | None,
|
158
|
+
join_time: int,
|
159
|
+
created: int,
|
160
|
+
last_message: Message | None,
|
161
|
+
type: ChatType | str,
|
162
|
+
last_fire_delayed_error_time: int,
|
163
|
+
last_delayed_update_time: int,
|
164
|
+
prev_message_id: str | None,
|
165
|
+
options: dict[str, bool],
|
166
|
+
modified: int,
|
167
|
+
last_event_time: int,
|
168
|
+
id: int,
|
169
|
+
status: str,
|
170
|
+
participants: dict[str, int],
|
171
|
+
) -> None:
|
172
|
+
self.cid = cid
|
173
|
+
self.owner = owner
|
174
|
+
self.has_bots = has_bots
|
175
|
+
self.join_time = join_time
|
176
|
+
self.created = created
|
177
|
+
self.last_message = last_message
|
178
|
+
self.type = type
|
179
|
+
self.last_fire_delayed_error_time = last_fire_delayed_error_time
|
180
|
+
self.last_delayed_update_time = last_delayed_update_time
|
181
|
+
self.prev_message_id = prev_message_id
|
182
|
+
self.options = options
|
183
|
+
self.modified = modified
|
184
|
+
self.last_event_time = last_event_time
|
185
|
+
self.id = id
|
186
|
+
self.status = status
|
187
|
+
self.participants = participants
|
188
|
+
|
189
|
+
@classmethod
|
190
|
+
def from_dict(cls, data: dict[Any, Any]) -> "Dialog":
|
191
|
+
return cls(
|
192
|
+
cid=data.get("cid"),
|
193
|
+
owner=data["owner"],
|
194
|
+
has_bots=data.get("hasBots"),
|
195
|
+
join_time=data["joinTime"],
|
196
|
+
created=data["created"],
|
197
|
+
last_message=Message.from_dict(data["lastMessage"])
|
198
|
+
if data.get("lastMessage")
|
199
|
+
else None,
|
200
|
+
type=ChatType(data["type"]),
|
201
|
+
last_fire_delayed_error_time=data["lastFireDelayedErrorTime"],
|
202
|
+
last_delayed_update_time=data["lastDelayedUpdateTime"],
|
203
|
+
prev_message_id=data.get("prevMessageId"),
|
204
|
+
options=data.get("options", {}),
|
205
|
+
modified=data["modified"],
|
206
|
+
last_event_time=data["lastEventTime"],
|
207
|
+
id=data["id"],
|
208
|
+
status=data["status"],
|
209
|
+
participants=data["participants"],
|
210
|
+
)
|
211
|
+
|
212
|
+
@override
|
213
|
+
def __repr__(self) -> str:
|
214
|
+
return f"Dialog(id={self.id!r}, owner={self.owner!r}, type={self.type!r}, last_message={self.last_message!r})"
|
215
|
+
|
216
|
+
@override
|
217
|
+
def __str__(self) -> str:
|
218
|
+
return f"Dialog {self.id} ({self.type})"
|
219
|
+
|
220
|
+
|
221
|
+
class Chat:
|
222
|
+
def __init__(
|
223
|
+
self,
|
224
|
+
participants_count: int,
|
225
|
+
access: AccessType | str,
|
226
|
+
invited_by: int | None,
|
227
|
+
link: str | None,
|
228
|
+
chat_type: ChatType | str,
|
229
|
+
title: str | None,
|
230
|
+
last_fire_delayed_error_time: int,
|
231
|
+
last_delayed_update_time: int,
|
232
|
+
options: dict[str, bool],
|
233
|
+
base_raw_icon_url: str | None,
|
234
|
+
base_icon_url: str | None,
|
235
|
+
description: str | None,
|
236
|
+
modified: int,
|
237
|
+
id_: int,
|
238
|
+
admin_participants: dict[int, dict[Any, Any]],
|
239
|
+
participants: dict[int, int],
|
240
|
+
owner: int,
|
241
|
+
join_time: int,
|
242
|
+
created: int,
|
243
|
+
last_message: Message | None,
|
244
|
+
prev_message_id: str | None,
|
245
|
+
last_event_time: int,
|
246
|
+
messages_count: int,
|
247
|
+
admins: list[int],
|
248
|
+
restrictions: int | None,
|
249
|
+
status: str,
|
250
|
+
cid: int,
|
251
|
+
) -> None:
|
252
|
+
self.participants_count = participants_count
|
253
|
+
self.access = access
|
254
|
+
self.invited_by = invited_by
|
255
|
+
self.link = link
|
256
|
+
self.type = chat_type
|
257
|
+
self.title = title
|
258
|
+
self.last_fire_delayed_error_time = last_fire_delayed_error_time
|
259
|
+
self.last_delayed_update_time = last_delayed_update_time
|
260
|
+
self.options = options
|
261
|
+
self.base_raw_icon_url = base_raw_icon_url
|
262
|
+
self.base_icon_url = base_icon_url
|
263
|
+
self.description = description
|
264
|
+
self.modified = modified
|
265
|
+
self.id = id_
|
266
|
+
self.admin_participants = admin_participants
|
267
|
+
self.participants = participants
|
268
|
+
self.owner = owner
|
269
|
+
self.join_time = join_time
|
270
|
+
self.created = created
|
271
|
+
self.last_message = last_message
|
272
|
+
self.prev_message_id = prev_message_id
|
273
|
+
self.last_event_time = last_event_time
|
274
|
+
self.messages_count = messages_count
|
275
|
+
self.admins = admins
|
276
|
+
self.restrictions = restrictions
|
277
|
+
self.status = status
|
278
|
+
self.cid = cid
|
279
|
+
|
280
|
+
@classmethod
|
281
|
+
def from_dict(cls, data: dict[Any, Any]) -> "Chat":
|
282
|
+
raw_admins = data.get("adminParticipants", {}) or {}
|
283
|
+
admin_participants: dict[int, dict[Any, Any]] = {
|
284
|
+
int(k): v for k, v in raw_admins.items()
|
285
|
+
}
|
286
|
+
raw_participants = data.get("participants", {}) or {}
|
287
|
+
participants: dict[int, int] = {int(k): v for k, v in raw_participants.items()}
|
288
|
+
last_msg = (
|
289
|
+
Message.from_dict(data["lastMessage"]) if data.get("lastMessage") else None
|
290
|
+
)
|
291
|
+
return cls(
|
292
|
+
participants_count=data.get("participantsCount", 0),
|
293
|
+
access=AccessType(data.get("access", AccessType.PUBLIC.value)),
|
294
|
+
invited_by=data.get("invitedBy"),
|
295
|
+
link=data.get("link"),
|
296
|
+
base_raw_icon_url=data.get("baseRawIconUrl"),
|
297
|
+
base_icon_url=data.get("baseIconUrl"),
|
298
|
+
description=data.get("description"),
|
299
|
+
chat_type=ChatType(data.get("type", ChatType.CHAT.value)),
|
300
|
+
title=data.get("title"),
|
301
|
+
last_fire_delayed_error_time=data.get("lastFireDelayedErrorTime", 0),
|
302
|
+
last_delayed_update_time=data.get("lastDelayedUpdateTime", 0),
|
303
|
+
options=data.get("options", {}),
|
304
|
+
modified=data.get("modified", 0),
|
305
|
+
id_=data.get("id", 0),
|
306
|
+
admin_participants=admin_participants,
|
307
|
+
participants=participants,
|
308
|
+
owner=data.get("owner", 0),
|
309
|
+
join_time=data.get("joinTime", 0),
|
310
|
+
created=data.get("created", 0),
|
311
|
+
last_message=last_msg,
|
312
|
+
prev_message_id=data.get("prevMessageId"),
|
313
|
+
last_event_time=data.get("lastEventTime", 0),
|
314
|
+
messages_count=data.get("messagesCount", 0),
|
315
|
+
admins=data.get("admins", []),
|
316
|
+
restrictions=data.get("restrictions"),
|
317
|
+
status=data.get("status", ""),
|
318
|
+
cid=data.get("cid", 0),
|
319
|
+
)
|
320
|
+
|
321
|
+
@override
|
322
|
+
def __repr__(self) -> str:
|
323
|
+
return f"Chat(id={self.id!r}, title={self.title!r}, type={self.type!r})"
|
324
|
+
|
325
|
+
@override
|
326
|
+
def __str__(self) -> str:
|
327
|
+
return f"{self.title} ({self.type})"
|
328
|
+
|
329
|
+
|
330
|
+
class Channel(Chat):
|
331
|
+
@override
|
332
|
+
def __repr__(self) -> str:
|
333
|
+
return f"Channel(id={self.id!r}, title={self.title!r})"
|
334
|
+
|
335
|
+
@override
|
336
|
+
def __str__(self) -> str:
|
337
|
+
return f"Channel: {self.title}"
|
338
|
+
|
339
|
+
|
340
|
+
class User:
|
341
|
+
def __init__(
|
342
|
+
self,
|
343
|
+
account_status: int,
|
344
|
+
update_time: int,
|
345
|
+
id: int,
|
346
|
+
names: list[Names],
|
347
|
+
options: list[str] | None = None,
|
348
|
+
base_url: str | None = None,
|
349
|
+
base_raw_url: str | None = None,
|
350
|
+
photo_id: int | None = None,
|
351
|
+
description: str | None = None,
|
352
|
+
gender: int | None = None,
|
353
|
+
link: str | None = None,
|
354
|
+
web_app: str | None = None,
|
355
|
+
menu_button: dict[str, Any] | None = None,
|
356
|
+
) -> None:
|
357
|
+
self.account_status = account_status
|
358
|
+
self.update_time = update_time
|
359
|
+
self.id = id
|
360
|
+
self.names = names
|
361
|
+
self.options = options or []
|
362
|
+
self.base_url = base_url
|
363
|
+
self.base_raw_url = base_raw_url
|
364
|
+
self.photo_id = photo_id
|
365
|
+
self.description = description
|
366
|
+
self.gender = gender
|
367
|
+
self.link = link
|
368
|
+
self.web_app = web_app
|
369
|
+
self.menu_button = menu_button
|
370
|
+
|
371
|
+
@classmethod
|
372
|
+
def from_dict(cls, data: dict[str, Any]) -> "User":
|
373
|
+
return cls(
|
374
|
+
account_status=data["accountStatus"],
|
375
|
+
update_time=data["updateTime"],
|
376
|
+
id=data["id"],
|
377
|
+
names=[Names.from_dict(n) for n in data.get("names", [])],
|
378
|
+
options=data.get("options"),
|
379
|
+
base_url=data.get("baseUrl"),
|
380
|
+
base_raw_url=data.get("baseRawUrl"),
|
381
|
+
photo_id=data.get("photoId"),
|
382
|
+
description=data.get("description"),
|
383
|
+
gender=data.get("gender"),
|
384
|
+
link=data.get("link"),
|
385
|
+
web_app=data.get("webApp"),
|
386
|
+
menu_button=data.get("menuButton"),
|
387
|
+
)
|
388
|
+
|
389
|
+
@override
|
390
|
+
def __repr__(self) -> str:
|
391
|
+
return f"User(id={self.id!r}, names={self.names!r}, status={self.account_status!r})"
|
392
|
+
|
393
|
+
@override
|
394
|
+
def __str__(self) -> str:
|
395
|
+
return f"User {self.id}: {', '.join(str(n) for n in self.names)}"
|
396
|
+
|
397
|
+
|
398
|
+
class Attach:
|
399
|
+
def __init__(
|
400
|
+
self,
|
401
|
+
_type: AttachType,
|
402
|
+
video_id: int | None = None,
|
403
|
+
photo_token: str | None = None,
|
404
|
+
file_id: int | None = None,
|
405
|
+
token: str | None = None,
|
406
|
+
) -> None:
|
407
|
+
self.type = _type
|
408
|
+
self.video_id = video_id
|
409
|
+
self.photo_token = photo_token
|
410
|
+
self.file_id = file_id
|
411
|
+
self.token = token
|
412
|
+
|
413
|
+
@classmethod
|
414
|
+
def from_dict(cls, data: dict[str, Any]) -> "Attach":
|
415
|
+
return cls(
|
416
|
+
_type=AttachType(data["type"]),
|
417
|
+
video_id=data.get("videoId"),
|
418
|
+
photo_token=data.get("photoToken"),
|
419
|
+
file_id=data.get("fileId"),
|
420
|
+
token=data.get("token"),
|
421
|
+
)
|
422
|
+
|
423
|
+
@override
|
424
|
+
def __repr__(self) -> str:
|
425
|
+
return (
|
426
|
+
f"Attach(type={self.type!r}, video_id={self.video_id!r}, "
|
427
|
+
f"photo_token={self.photo_token!r}, file_id={self.file_id!r}, token={self.token!r})"
|
428
|
+
)
|
429
|
+
|
430
|
+
@override
|
431
|
+
def __str__(self) -> str:
|
432
|
+
return f"Attach: {self.type}"
|
pymax/utils.py
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
from typing import Any
|
2
|
+
|
3
|
+
import lz4.block
|
4
|
+
import msgpack
|
5
|
+
|
6
|
+
|
7
|
+
def unpack_packet(data: bytes) -> None | dict[str, Any]:
|
8
|
+
ver = int.from_bytes(data[0:1], "big")
|
9
|
+
cmd = int.from_bytes(data[1:3], "big")
|
10
|
+
seq = int.from_bytes(data[3:4], "big")
|
11
|
+
opcode = int.from_bytes(data[4:6], "big")
|
12
|
+
packed_len = int.from_bytes(data[6:10], "big", signed=False)
|
13
|
+
comp_flag = packed_len >> 24
|
14
|
+
payload_length = packed_len & 0xFFFFFF
|
15
|
+
payload_bytes = data[10 : 10 + payload_length]
|
16
|
+
if comp_flag != 0:
|
17
|
+
compressed_data = payload_bytes
|
18
|
+
try:
|
19
|
+
payload_bytes = lz4.block.decompress(compressed_data, uncompressed_size=255)
|
20
|
+
except lz4.block.LZ4BlockError:
|
21
|
+
return None
|
22
|
+
payload = msgpack.unpackb(payload_bytes, raw=False)
|
23
|
+
return {"ver": ver, "cmd": cmd, "seq": seq, "opcode": opcode, "payload": payload}
|
24
|
+
|
25
|
+
|
26
|
+
# ToDo: Add lz4 compression
|
27
|
+
def pack_packet(
|
28
|
+
ver: int, cmd: int, seq: int, opcode: int, payload: dict[str, Any]
|
29
|
+
) -> bytes:
|
30
|
+
ver_b = ver.to_bytes(1, "big")
|
31
|
+
cmd_b = cmd.to_bytes(2, "big")
|
32
|
+
seq_b = seq.to_bytes(1, "big")
|
33
|
+
opcode_b = opcode.to_bytes(2, "big")
|
34
|
+
payload_bytes = msgpack.packb(payload)
|
35
|
+
if payload_bytes is None:
|
36
|
+
payload_bytes = b""
|
37
|
+
payload_len_b = len(payload_bytes).to_bytes(4, "big")
|
38
|
+
return ver_b + cmd_b + seq_b + opcode_b + payload_len_b + payload_bytes
|
@@ -1,4 +0,0 @@
|
|
1
|
-
maxapi_python-0.1.1.dist-info/METADATA,sha256=uHYKlxE6NA9cmATGtlE_AhF05iJarJmX4fKLCnuMbkE,4812
|
2
|
-
maxapi_python-0.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
3
|
-
maxapi_python-0.1.1.dist-info/licenses/LICENSE,sha256=Ud-0SKeXO_yA02Bb1nMDnEaSGwz2OqNlfGQbk0IzqPI,1085
|
4
|
-
maxapi_python-0.1.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|