Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions examples/telegram_bridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,17 @@ async def handle_message(message: Message) -> None:
async with session.get(video.url) as response:
response.raise_for_status() # Проверка на ошибки HTTP
video_bytes = BytesIO(await response.read())
video_bytes.name = response.headers.get("X-File-Name")
video_bytes.name = response.headers.get(
"X-File-Name"
)

# Отправляем видео через телеграм бота
await telegram_bot.send_video(
chat_id=tg_id,
caption=f"{sender.names[0].name}: {message.text}",
video=types.BufferedInputFile(
video_bytes.getvalue(), filename=video_bytes.name
video_bytes.getvalue(),
filename=video_bytes.name,
),
)

Expand All @@ -102,14 +105,17 @@ async def handle_message(message: Message) -> None:
async with session.get(attach.base_url) as response:
response.raise_for_status() # Проверка на ошибки HTTP
photo_bytes = BytesIO(await response.read())
photo_bytes.name = response.headers.get("X-File-Name")
photo_bytes.name = response.headers.get(
"X-File-Name"
)

# Отправляем фото через телеграм бота
await telegram_bot.send_photo(
chat_id=tg_id,
caption=f"{sender.names[0].name}: {message.text}",
photo=types.BufferedInputFile(
photo_bytes.getvalue(), filename=photo_bytes.name
photo_bytes.getvalue(),
filename=photo_bytes.name,
),
)

Expand All @@ -136,7 +142,9 @@ async def handle_message(message: Message) -> None:
async with session.get(file.url) as response:
response.raise_for_status() # Проверка на ошибки HTTP
file_bytes = BytesIO(await response.read())
file_bytes.name = response.headers.get("X-File-Name")
file_bytes.name = response.headers.get(
"X-File-Name"
)

# Отправляем файл через телеграм бота
await telegram_bot.send_document(
Expand Down
48 changes: 48 additions & 0 deletions src/pymax/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,45 +9,93 @@
from .exceptions import (
InvalidPhoneError,
LoginError,
ResponseError,
ResponseStructureError,
SocketNotConnectedError,
SocketSendError,
WebSocketNotConnectedError,
)
from .static.enum import (
AccessType,
AttachType,
AuthType,
ChatType,
ContactAction,
DeviceType,
ElementType,
FormattingType,
MarkupType,
MessageStatus,
MessageType,
Opcode,
)
from .types import (
Channel,
Chat,
Contact,
ControlAttach,
Dialog,
Element,
FileAttach,
FileRequest,
Me,
Member,
Message,
MessageLink,
Name,
Names,
PhotoAttach,
Presence,
ReactionCounter,
ReactionInfo,
Session,
User,
VideoAttach,
VideoRequest,
)

__author__ = "ink-developer"

__all__ = [
# Перечисления и константы
"AccessType",
"AttachType",
"AuthType",
"ContactAction",
"FormattingType",
"MarkupType",
# Типы данных
"Channel",
"Chat",
"ChatType",
"Contact",
"ControlAttach",
"DeviceType",
"Dialog",
"Element",
"ElementType",
"FileAttach",
"FileRequest",
"Me",
"Member",
"MessageLink",
"Name",
"Names",
"PhotoAttach",
"Presence",
"ReactionCounter",
"ReactionInfo",
"Session",
"VideoAttach",
"VideoRequest",
# Исключения
"InvalidPhoneError",
"LoginError",
"WebSocketNotConnectedError",
"ResponseError",
"ResponseStructureError",
"SocketNotConnectedError",
"SocketSendError",
# Клиент
"MaxClient",
"Message",
Expand Down
6 changes: 4 additions & 2 deletions src/pymax/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import ssl
import time
from pathlib import Path
from typing import Literal
from typing import Any, Literal

from typing_extensions import override

Expand Down Expand Up @@ -88,7 +88,9 @@ def __init__(
self._circuit_breaker: bool = False
self._last_error_time: float = 0.0
self._device_id = self._database.get_device_id()
self._file_upload_waiters: dict[int, asyncio.Future[dict[str, Any]]] = {}
self._file_upload_waiters: dict[
int, asyncio.Future[dict[str, Any]]
] = {}
self._token = self._database.get_auth_token() or token
self.user_agent = headers
self._send_fake_telemetry: bool = send_fake_telemetry
Expand Down
16 changes: 12 additions & 4 deletions src/pymax/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@


class BaseFile(ABC):
def __init__(self, url: str | None = None, path: str | None = None) -> None:
def __init__(
self, url: str | None = None, path: str | None = None
) -> None:
self.url = url
self.path = path

Expand Down Expand Up @@ -45,7 +47,9 @@ class Photo(BaseFile):
".bmp",
} # FIXME: костыль ✅

def __init__(self, url: str | None = None, path: str | None = None) -> None:
def __init__(
self, url: str | None = None, path: str | None = None
) -> None:
super().__init__(url, path)

def validate_photo(self) -> tuple[str, str] | None:
Expand All @@ -67,7 +71,9 @@ def validate_photo(self) -> tuple[str, str] | None:
mime_type = mimetypes.guess_type(self.url)[0]

if not mime_type or not mime_type.startswith("image/"):
raise ValueError(f"URL does not appear to be an image: {self.url}")
raise ValueError(
f"URL does not appear to be an image: {self.url}"
)

return (extension[1:], mime_type)
return None
Expand All @@ -84,7 +90,9 @@ async def read(self) -> bytes:


class File(BaseFile):
def __init__(self, url: str | None = None, path: str | None = None) -> None:
def __init__(
self, url: str | None = None, path: str | None = None
) -> None:
self.file_name: str = ""
if path:
self.file_name = Path(path).name
Expand Down
11 changes: 6 additions & 5 deletions src/pymax/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@

import websockets

from pymax.static.constant import DEFAULT_USER_AGENT

from .filters import Filter
from .payloads import UserAgentPayload
from .static.constant import DEFAULT_TIMEOUT
Expand Down Expand Up @@ -50,14 +48,15 @@ def __init__(self, logger: Logger) -> None:
self._pending: dict[int, asyncio.Future[dict[str, Any]]] = {}
self._recv_task: asyncio.Task[Any] | None = None
self._incoming: asyncio.Queue[dict[str, Any]] | None = None
self._file_upload_waiters: dict[int, asyncio.Future[dict[str, Any]]] = {}
self._file_upload_waiters: dict[
int, asyncio.Future[dict[str, Any]]
] = {}
self.user_agent = UserAgentPayload()
self._outgoing: asyncio.Queue[dict[str, Any]] | None = None
self._outgoing_task: asyncio.Task[Any] | None = None
self._error_count: int = 0
self._circuit_breaker: bool = False
self._last_error_time: float = 0.0
self.user_agent = DEFAULT_USER_AGENT
self._session_id: int
self._action_id: int = 0
self._current_screen: str = "chats_list_tab"
Expand All @@ -70,7 +69,9 @@ def __init__(self, logger: Logger) -> None:
self._on_message_delete_handlers: list[
tuple[Callable[[Message], Any], Filter | None]
] = []
self._on_start_handler: Callable[[], Any | Awaitable[Any]] | None = None
self._on_start_handler: Callable[[], Any | Awaitable[Any]] | None = (
None
)
self._background_tasks: set[asyncio.Task[Any]] = set()
self._ssl_context: ssl.SSLContext
self._socket: socket.socket | None = None
Expand Down
12 changes: 9 additions & 3 deletions src/pymax/mixins/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ async def _send_code(self, code: str, token: str) -> dict[str, Any]:
auth_token_type=AuthType.CHECK_CODE,
).model_dump(by_alias=True)

data = await self._send_and_wait(opcode=Opcode.AUTH, payload=payload)
data = await self._send_and_wait(
opcode=Opcode.AUTH, payload=payload
)
self.logger.debug(
"Send code response opcode=%s seq=%s",
data.get("opcode"),
Expand Down Expand Up @@ -128,7 +130,9 @@ async def _submit_reg_info(
self.logger.error("Submit registration info failed", exc_info=True)
raise RuntimeError("Submit registration info failed")

async def _register(self, first_name: str, last_name: str | None = None) -> None:
async def _register(
self, first_name: str, last_name: str | None = None
) -> None:
self.logger.info("Starting registration flow")

request_code_payload = await self._request_code(self.phone)
Expand All @@ -146,7 +150,9 @@ async def _register(self, first_name: str, last_name: str | None = None) -> None

registration_response = await self._send_code(code, temp_token)
token: str | None = (
registration_response.get("tokenAttrs", {}).get("REGISTER", {}).get("token")
registration_response.get("tokenAttrs", {})
.get("REGISTER", {})
.get("token")
)
if not token:
self.logger.critical("Failed to register, token not received")
Expand Down
Loading