Skip to content

Запрос функциональности: нативная поддержка аудио и видеокружков в maxapi-python #73

Description

@dabankrot

Библиотека: maxapi-python 2.3.1
Дата: 2026-07-09
Контекст: Продакшн-использование в коннекторе Bitrix24 Open Line (max-connector), который пересылает медиа между CRM Bitrix и мессенджером MAX.


Краткое описание

maxapi-python 2.3.1 не умеет отправлять и принимать аудиосообщения (войсы) и видеокружки. Сейчас это работает через 10+ monkey-patch'ей во время выполнения. Ниже — список проблем для нативного исправления в библиотеке.


1. UploadPayload — нет поля type

Проблема: UploadPayload содержит только поля count и profile. Сервер MAX в opcode VIDEO_UPLOAD (135) принимает параметр type для выбора типа загрузки:

type Значение Примечание
0 Обычное видео Текущее поведение по умолчанию
1 Видеокружок VIDEO_MESSAGE
2 Аудио Голосовое сообщение
3 Сторис (не тестировалось)

Запрос: Добавить поле type: int = 0 в UploadPayload и прокидывать его в upload_video() / upload_file().


2. upload_video() — нет параметра type

Проблема: UploadService.upload_video() отправляет VIDEO_UPLOAD без type, сервер всегда обрабатывает как обычное видео (type=0). Видеокружки (type=1) отправить нельзя.

Запрос: Добавить параметр type (или video_type) в upload_video(), чтобы вызов мог указать type=1 для кружков.


3. Загрузка аудио — нет нативной поддержки

Проблема: Нет класса AudioFile и нет способа загрузить аудио как войс. File грузится через FILE_UPLOAD, но MAX ожидает аудио через VIDEO_UPLOAD с type=2. Сервер возвращает audioId + token, а исходящее сообщение требует audio-специфичный payload.

Запрос:

  • Добавить класс AudioFile (аналог File / Video).
  • Маршрутизировать аудио через VIDEO_UPLOAD с type=2.
  • Добавить AttachAudioPayload с полями: _type=AUDIO, audioId, token, duration, wave.
  • Зарегистрировать AttachAudioPayload в SendMessagePayloadMessage.attaches, EditMessagePayload.attachments, ForwardMessagePayloadMessage.attaches через Union.

4. VideoUploadSignal — не принимает audioId

Проблема: При загрузке аудио (type=2) сервер шлёт NOTIF_ATTACH (opcode 136) с audioId вместо videoId. VideoUploadSignal принимает только videoId — событие завершения загрузки молча игнорируется, future никогда не резолвится.

Текущий воркэраунд: Патч validation_alias на AliasChoices("videoId", "audioId").

Запрос: Добавить audioId как принимаемый алиас для video_id в VideoUploadSignal, либо создать отдельную модель AudioUploadSignal.


5. resolve_attach — игнорирует события аудио-загрузки

Проблема: resolve_attach() валидирует VideoUploadSignal (ожидает videoId). Для аудио сервер шлёт audioId — валидация падает, событие игнорируется. Future загрузки никогда не завершается, возникает таймаут.

Запрос: resolve_attach должен обрабатывать audioId-payload'ы и возвращать VIDEO_READY (или новый тип события AUDIO_READY).


6. VideoRequest — поле cache обязательно, но сервер его не присылает

Проблема: client.get_video_by_id() возвращает модель VideoRequest с обязательным полем cache. Сервер иногда возвращает {'MP4_480': 'https://...'} без cacheValidationError. Воспроизводится при скачивании видеокружков.

Запрос: Сделать cache опциональным в VideoRequest, либо обрабатывать случай, когда сервер возвращает URL напрямую в ключах без обёртки cache.


7. Класс Video — нет поля type для отличия кружка от обычного видео

Проблема: Video не имеет поля type для различения обычного видео и кружка. Сервер использует video_type=1 для кружков в VideoAttachment.

Запрос: Добавить поле video_type (или type) в Video и VideoAttachment со значениями:

  • 0 — обычное видео
  • 1 — видеокружок (VIDEO_MESSAGE)

8. read_message — отметка сообщений прочитанными

Проблема: Нет публичного метода для отметки входящих сообщений как прочитанных. Мы вызываем client.read_message(), который существует, но не задокументирован.

Запрос: Официально expose'нуть и задокументировать read_message(message_id, chat_id) как публичный метод API.


9. Устойчивость сессий — обработка FAIL_LOGOUT_ALL

Проблема: Когда сервер MAX инвалидирует все сессии аккаунта (ошибка login.token / FAIL_LOGOUT_ALL), Client.start() выбрасывает исключение, аккаунт остаётся отключённым. Нет callback'а или события для этого состояния — коннектор не может отличить «временная сетевая ошибка» от «сессия навсегда инвалидирована, нужен re-pairing по SMS».

Запрос: Предоставить структурированное событие или исключение для FAIL_LOGOUT_ALL, чтобы коннекторы могли запустить re-pairing (SMS-флоу) вместо слепых ретраев с мёртвым токеном.


Приоритеты

# Проблема Критичность Влияние
1 UploadPayload без type Высокая Блокирует отправку аудио+кружков
2 upload_video без type Высокая Блокирует отправку кружков
3 Нет загрузки аудио Высокая Блокирует отправку аудио
4 VideoUploadSignal audioId Высокая Загрузка аудио не завершается
5 resolve_attach игнорирует аудио Высокая Загрузка аудио не завершается
6 VideoRequest cache обязательно Средняя Скачивание кружков падает
7 Video без type Низкая Нельзя отличить кружок/обычное
8 read_message не задокументирован Низкая Нет публичного API для read-receipts
9 FAIL_LOGOUT_ALL обработка Средняя Молчаливая инвалидация сессии

Окружение

  • maxapi-python: 2.3.1
  • Python: 3.12
  • Сервер MAX: api.oneme.ru

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions