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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions