chore(openspec): archive add-video-support and sync main specs
This commit is contained in:
@@ -29,7 +29,8 @@ SHALL не выводиться в поток вывода.
|
|||||||
### Requirement: Создание альбомов и фотографий
|
### Requirement: Создание альбомов и фотографий
|
||||||
Скрипт SHALL создавать заданное параметрами число альбомов и фотографий в каждом от имени
|
Скрипт SHALL создавать заданное параметрами число альбомов и фотографий в каждом от имени
|
||||||
аутентифицированного владельца через `POST /api/albums` и
|
аутентифицированного владельца через `POST /api/albums` и
|
||||||
`POST /api/albums/:id/photos`. Названия альбомов SHALL содержать метку прогона.
|
`POST /api/albums/:id/photos`. Названия альбомов SHALL содержать метку прогона. При
|
||||||
|
включённом флаге видео скрипт SHALL дополнительно загружать видео-фикстуры.
|
||||||
|
|
||||||
#### Scenario: Наполнение альбомами и фото
|
#### Scenario: Наполнение альбомами и фото
|
||||||
- **WHEN** скрипт запущен с числом альбомов и фотографий на альбом
|
- **WHEN** скрипт запущен с числом альбомов и фотографий на альбом
|
||||||
@@ -39,6 +40,10 @@ SHALL не выводиться в поток вывода.
|
|||||||
- **WHEN** задан числовой seed
|
- **WHEN** задан числовой seed
|
||||||
- **THEN** структура и параметры генерируемых данных детерминированы для этого seed
|
- **THEN** структура и параметры генерируемых данных детерминированы для этого seed
|
||||||
|
|
||||||
|
#### Scenario: Флаг видео
|
||||||
|
- **WHEN** скрипт запущен с включённым флагом видео
|
||||||
|
- **THEN** помимо изображений часть альбомов получает видео-фикстуры
|
||||||
|
|
||||||
### Requirement: Генерация изображений с EXIF
|
### Requirement: Генерация изображений с EXIF
|
||||||
Скрипт SHALL генерировать загружаемые изображения на лету. При доступной библиотеке Pillow
|
Скрипт SHALL генерировать загружаемые изображения на лету. При доступной библиотеке Pillow
|
||||||
он SHALL использовать JPEG с EXIF-метаданными (время съёмки, при необходимости GPS); при
|
он SHALL использовать JPEG с EXIF-метаданными (время съёмки, при необходимости GPS); при
|
||||||
@@ -109,3 +114,16 @@ HTTP-клиент; Pillow SHALL быть необязательной завис
|
|||||||
#### Scenario: Значения по умолчанию
|
#### Scenario: Значения по умолчанию
|
||||||
- **WHEN** цель запущена без параметров
|
- **WHEN** цель запущена без параметров
|
||||||
- **THEN** используются документированные значения по умолчанию
|
- **THEN** используются документированные значения по умолчанию
|
||||||
|
|
||||||
|
### Requirement: Наполнение видео
|
||||||
|
При включённом флаге видео скрипт SHALL загружать видео-фикстуру через общий эндпоинт
|
||||||
|
загрузки; если генерация видео недоступна, скрипт SHALL пропускать видео и продолжать без
|
||||||
|
ошибки.
|
||||||
|
|
||||||
|
#### Scenario: Видео включено
|
||||||
|
- **WHEN** включён флаг видео
|
||||||
|
- **THEN** в часть альбомов загружаются видео-фикстуры, различимые по метке прогона
|
||||||
|
|
||||||
|
#### Scenario: Генерация недоступна
|
||||||
|
- **WHEN** видео-инструменты недоступны, а флаг видео включён
|
||||||
|
- **THEN** скрипт пропускает видео и продолжает наполнение
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
Каждый физический объект SHALL иметь ровно одну запись в слое метаданных с ключом,
|
Каждый физический объект SHALL иметь ровно одну запись в слое метаданных с ключом,
|
||||||
MIME-типом, размером, габаритами и состоянием; фото SHALL ссылаться на объекты по
|
MIME-типом, размером, габаритами и состоянием; фото SHALL ссылаться на объекты по
|
||||||
ролям original, thumb, medium и preview.
|
ролям original, thumb, medium, preview и playback.
|
||||||
|
|
||||||
#### Scenario: Привязка ролей
|
#### Scenario: Привязка ролей
|
||||||
|
|
||||||
@@ -37,6 +37,11 @@ MIME-типом, размером, габаритами и состоянием;
|
|||||||
- **WHEN** варианты ещё не сгенерированы
|
- **WHEN** варианты ещё не сгенерированы
|
||||||
- **THEN** фото доступно с оригиналом, а thumb, medium и preview отсутствуют
|
- **THEN** фото доступно с оригиналом, а thumb, medium и preview отсутствуют
|
||||||
|
|
||||||
|
#### Scenario: Привязка роли воспроизведения
|
||||||
|
|
||||||
|
- **WHEN** видео обработано
|
||||||
|
- **THEN** медиа ссылается на объект playback наряду с оригиналом и постером
|
||||||
|
|
||||||
### Requirement: Совместные объекты
|
### Requirement: Совместные объекты
|
||||||
Несколько фото SHALL иметь возможность ссылаться на один и тот же физический
|
Несколько фото SHALL иметь возможность ссылаться на один и тот же физический
|
||||||
объект; перенос и копирование SHALL изменять только ссылки и SHALL не изменять
|
объект; перенос и копирование SHALL изменять только ссылки и SHALL не изменять
|
||||||
@@ -80,10 +85,11 @@ MIME-типом, размером, габаритами и состоянием;
|
|||||||
- **THEN** попытка повторяется до успешного удаления
|
- **THEN** попытка повторяется до успешного удаления
|
||||||
|
|
||||||
### Requirement: Генерация вариантов
|
### Requirement: Генерация вариантов
|
||||||
Генерация thumb и preview SHALL выполняться через надёжную очередь заданий с
|
Генерация вариантов SHALL выполняться через надёжную очередь заданий с
|
||||||
однократным выполнением и повтором при сбое; готовый результат SHALL
|
однократным выполнением и повтором при сбое; готовый результат SHALL
|
||||||
транслироваться подписчикам альбома. Очередь SHALL поддерживать настраиваемую
|
транслироваться подписчикам альбома. Очередь SHALL поддерживать настраиваемую
|
||||||
пропускную способность и SHALL обрабатывать более свежие фото раньше остальных.
|
пропускную способность, SHALL обрабатывать более свежие фото раньше остальных и
|
||||||
|
SHALL различать короткие задания изображений и длительные задания видео.
|
||||||
|
|
||||||
#### Scenario: Повтор после рестарта
|
#### Scenario: Повтор после рестарта
|
||||||
- **WHEN** процесс перезапускается с незавершёнными заданиями
|
- **WHEN** процесс перезапускается с незавершёнными заданиями
|
||||||
@@ -100,3 +106,7 @@ MIME-типом, размером, габаритами и состоянием;
|
|||||||
#### Scenario: Настраиваемая пропускная способность
|
#### Scenario: Настраиваемая пропускная способность
|
||||||
- **WHEN** задан уровень параллелизма генерации
|
- **WHEN** задан уровень параллелизма генерации
|
||||||
- **THEN** система обрабатывает варианты с этим уровнем параллелизма
|
- **THEN** система обрабатывает варианты с этим уровнем параллелизма
|
||||||
|
|
||||||
|
#### Scenario: Длительное задание видео
|
||||||
|
- **WHEN** выполняется длительная подготовка видео
|
||||||
|
- **THEN** задание удерживается на весь срок выполнения и не вытесняет генерацию вариантов изображений
|
||||||
|
|||||||
@@ -7,16 +7,25 @@
|
|||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
### Requirement: Загрузка фото
|
### Requirement: Загрузка фото
|
||||||
Пользователь с правом загрузки SHALL иметь возможность загружать фото по одному и массово.
|
Пользователь с правом загрузки SHALL иметь возможность загружать медиа (изображения и
|
||||||
|
видео) по одному и массово; система SHALL принимать ввод `image/*` и `video/*`.
|
||||||
|
|
||||||
#### Scenario: Успешная загрузка
|
#### Scenario: Успешная загрузка
|
||||||
- **WHEN** участник с правом загрузки отправляет файл изображения
|
- **WHEN** участник с правом загрузки отправляет файл изображения
|
||||||
- **THEN** система сохраняет оригинал и создаёт запись фото с метаданными
|
- **THEN** система сохраняет оригинал и создаёт запись фото с метаданными
|
||||||
|
|
||||||
|
#### Scenario: Успешная загрузка видео
|
||||||
|
- **WHEN** участник с правом загрузки отправляет видеофайл
|
||||||
|
- **THEN** система сохраняет оригинал и создаёт медиа-запись с признаком видео
|
||||||
|
|
||||||
#### Scenario: Загрузка без права
|
#### Scenario: Загрузка без права
|
||||||
- **WHEN** наблюдатель пытается загрузить фото
|
- **WHEN** наблюдатель пытается загрузить фото
|
||||||
- **THEN** система отклоняет запрос
|
- **THEN** система отклоняет запрос
|
||||||
|
|
||||||
|
#### Scenario: Неподдерживаемый файл
|
||||||
|
- **WHEN** загружается файл, не являющийся изображением или видео
|
||||||
|
- **THEN** система отклоняет загрузку
|
||||||
|
|
||||||
### Requirement: Варианты изображений
|
### Requirement: Варианты изображений
|
||||||
|
|
||||||
Система SHALL генерировать четыре варианта: thumb (200×200, квадратный кроп), medium
|
Система SHALL генерировать четыре варианта: thumb (200×200, квадратный кроп), medium
|
||||||
@@ -110,13 +119,17 @@ EXIF (дата, координаты, размеры).
|
|||||||
- **THEN** система отклоняет запрос
|
- **THEN** система отклоняет запрос
|
||||||
|
|
||||||
### Requirement: Ограничение размера загрузки
|
### Requirement: Ограничение размера загрузки
|
||||||
Система SHALL ограничивать размер загружаемых файлов и SHALL отвечать понятной ошибкой при
|
Система SHALL ограничивать размер загружаемых файлов отдельно для изображений и видео и
|
||||||
превышении лимита, а не ошибкой разбора формы.
|
SHALL отвечать понятной ошибкой при превышении лимита, а не ошибкой разбора формы.
|
||||||
|
|
||||||
#### Scenario: Превышение лимита
|
#### Scenario: Превышение лимита
|
||||||
- **WHEN** загружаемый файл превышает максимальный размер
|
- **WHEN** загружаемый файл превышает максимальный размер
|
||||||
- **THEN** система отклоняет загрузку с явной ошибкой о превышении размера
|
- **THEN** система отклоняет загрузку с явной ошибкой о превышении размера
|
||||||
|
|
||||||
|
#### Scenario: Превышение лимита видео
|
||||||
|
- **WHEN** загружаемое видео превышает лимит видео
|
||||||
|
- **THEN** система отклоняет загрузку с явной ошибкой о превышении размера
|
||||||
|
|
||||||
#### Scenario: Файл в пределах лимита
|
#### Scenario: Файл в пределах лимита
|
||||||
- **WHEN** файл не превышает лимит
|
- **WHEN** файл не превышает лимит
|
||||||
- **THEN** система принимает multipart-загрузку и обрабатывает фото
|
- **THEN** система принимает multipart-загрузку и обрабатывает фото
|
||||||
@@ -208,3 +221,20 @@ EXIF (дата, координаты, размеры).
|
|||||||
#### Scenario: Повторный показ без перезагрузки
|
#### Scenario: Повторный показ без перезагрузки
|
||||||
- **WHEN** сетка превью перерисовывается, а URL объектов не изменились
|
- **WHEN** сетка превью перерисовывается, а URL объектов не изменились
|
||||||
- **THEN** браузер отдаёт объекты из кэша без повторного запроса к бэкенду
|
- **THEN** браузер отдаёт объекты из кэша без повторного запроса к бэкенду
|
||||||
|
|
||||||
|
### Requirement: Медиа-запись фото
|
||||||
|
Данные фото SHALL включать вид медиа (`image` | `video`), длительность для видео и адрес
|
||||||
|
воспроизведения, когда видео-вариант готов; для изображений адрес воспроизведения
|
||||||
|
отсутствует.
|
||||||
|
|
||||||
|
#### Scenario: Запись изображения
|
||||||
|
- **WHEN** клиент получает данные изображения
|
||||||
|
- **THEN** вид медиа — изображение, длительность и адрес воспроизведения отсутствуют
|
||||||
|
|
||||||
|
#### Scenario: Запись видео без готового варианта
|
||||||
|
- **WHEN** клиент получает данные видео, а вариант ещё не готов
|
||||||
|
- **THEN** вид медиа — видео, длительность присутствует, адрес воспроизведения отсутствует
|
||||||
|
|
||||||
|
#### Scenario: Запись видео с готовым вариантом
|
||||||
|
- **WHEN** видео-вариант готов
|
||||||
|
- **THEN** данные медиа содержат адрес воспроизведения
|
||||||
|
|||||||
@@ -106,7 +106,8 @@ SHALL отображаться вне каркаса, но в общей тем
|
|||||||
### Requirement: Загрузка фотографий из рабочего стола
|
### Requirement: Загрузка фотографий из рабочего стола
|
||||||
Загрузка SHALL запускаться действием в тулбаре; перетаскивание файлов над альбомом SHALL
|
Загрузка SHALL запускаться действием в тулбаре; перетаскивание файлов над альбомом SHALL
|
||||||
показывать оверлей и загружать их; пустой альбом SHALL показывать подсказку-зону загрузки.
|
показывать оверлей и загружать их; пустой альбом SHALL показывать подсказку-зону загрузки.
|
||||||
Загрузка SHALL быть доступна только ролям с правом загрузки.
|
Загрузка SHALL быть доступна только ролям с правом загрузки; принимать SHALL изображения и
|
||||||
|
видео.
|
||||||
|
|
||||||
#### Scenario: Перетаскивание
|
#### Scenario: Перетаскивание
|
||||||
- **WHEN** пользователь с правом загрузки перетаскивает файлы над альбомом
|
- **WHEN** пользователь с правом загрузки перетаскивает файлы над альбомом
|
||||||
@@ -116,6 +117,10 @@ SHALL отображаться вне каркаса, но в общей тем
|
|||||||
- **WHEN** пользователь открывает альбом без фото и имеет право загрузки
|
- **WHEN** пользователь открывает альбом без фото и имеет право загрузки
|
||||||
- **THEN** в центре показана зона-подсказка загрузки
|
- **THEN** в центре показана зона-подсказка загрузки
|
||||||
|
|
||||||
|
#### Scenario: Загрузка видео
|
||||||
|
- **WHEN** пользователь с правом загрузки выбирает или перетаскивает видеофайл
|
||||||
|
- **THEN** видео загружается в альбом наравне с изображениями
|
||||||
|
|
||||||
### Requirement: Темы и графитовый хром
|
### Requirement: Темы и графитовый хром
|
||||||
Тёмная тема SHALL использовать графитовый хром Lightroom и SHALL применяться по умолчанию;
|
Тёмная тема SHALL использовать графитовый хром Lightroom и SHALL применяться по умолчанию;
|
||||||
нейтральная тема SHALL быть тёплым графитом; остальные темы SHALL оставаться доступными, а
|
нейтральная тема SHALL быть тёплым графитом; остальные темы SHALL оставаться доступными, а
|
||||||
@@ -590,3 +595,40 @@ Ctrl/Cmd-клик — добавить или убрать, Shift-клик —
|
|||||||
|
|
||||||
- **WHEN** для фото доступен только оригинал или только миниатюра
|
- **WHEN** для фото доступен только оригинал или только миниатюра
|
||||||
- **THEN** показывается доступный вариант, и сетка отображается корректно
|
- **THEN** показывается доступный вариант, и сетка отображается корректно
|
||||||
|
|
||||||
|
### Requirement: Воспроизведение видео в просмотре
|
||||||
|
Видео в режиме просмотра SHALL воспроизводиться встроенным плеером с нативными контролами и
|
||||||
|
постером до готовности варианта; зум, панорамирование и режим панорамы SHALL к видео не
|
||||||
|
применяться, а действия скачивания, переноса, копирования и удаления SHALL оставаться доступными.
|
||||||
|
|
||||||
|
#### Scenario: Плеер
|
||||||
|
- **WHEN** пользователь открывает видео в режиме просмотра
|
||||||
|
- **THEN** показывается встроенный плеер, а до готовности варианта — постер
|
||||||
|
|
||||||
|
#### Scenario: Перемотка
|
||||||
|
- **WHEN** пользователь перематывает воспроизведение
|
||||||
|
- **THEN** плеер показывает запрошенный момент видео
|
||||||
|
|
||||||
|
#### Scenario: Готовность на лету
|
||||||
|
- **WHEN** вариант видео становится готов, пока просмотр открыт
|
||||||
|
- **THEN** плеер становится доступен без перезагрузки страницы
|
||||||
|
|
||||||
|
#### Scenario: Действия над видео
|
||||||
|
- **WHEN** открыто видео в режиме просмотра
|
||||||
|
- **THEN** доступны скачивание оригинала, перенос, копирование и удаление по правам
|
||||||
|
|
||||||
|
### Requirement: Плитка видео в сетке
|
||||||
|
Плитка видео в сетке SHALL показывать постер, признак видео и длительность; открытие плитки
|
||||||
|
SHALL открывать режим просмотра.
|
||||||
|
|
||||||
|
#### Scenario: Постер и признак
|
||||||
|
- **WHEN** видео показано в сетке
|
||||||
|
- **THEN** плитка показывает постер, значок воспроизведения и длительность
|
||||||
|
|
||||||
|
#### Scenario: Постер не готов
|
||||||
|
- **WHEN** постер ещё не готов
|
||||||
|
- **THEN** плитка показывает плейсхолдер и сетка отображается корректно
|
||||||
|
|
||||||
|
#### Scenario: Открытие из сетки
|
||||||
|
- **WHEN** пользователь открывает плитку видео
|
||||||
|
- **THEN** открывается режим просмотра видео
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
# videos Specification
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
Поддержка видео в альбомах: приём файла, фоновая подготовка web-совместимого варианта,
|
||||||
|
постер-кадр и воспроизведение в браузере.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
### Requirement: Приём видео
|
||||||
|
Участник с правом загрузки SHALL загружать видео в альбом; система SHALL принимать ввод
|
||||||
|
`video/*` и SHALL отклонять файлы сверх лимита видео понятной ошибкой о превышении размера.
|
||||||
|
|
||||||
|
#### Scenario: Успешная загрузка видео
|
||||||
|
- **WHEN** участник с правом загрузки отправляет видеофайл в пределах лимита
|
||||||
|
- **THEN** система сохраняет оригинал и создаёт медиа-запись с признаком видео
|
||||||
|
|
||||||
|
#### Scenario: Превышение лимита видео
|
||||||
|
- **WHEN** загружается файл больше лимита видео
|
||||||
|
- **THEN** система отклоняет загрузку с явной ошибкой о превышении размера
|
||||||
|
|
||||||
|
#### Scenario: Не медиафайл
|
||||||
|
- **WHEN** загружается файл, не являющийся изображением или видео
|
||||||
|
- **THEN** система отклоняет загрузку
|
||||||
|
|
||||||
|
### Requirement: Метаданные видео
|
||||||
|
При обработке система SHALL извлекать длительность, размеры кадра и поворот и SHALL
|
||||||
|
возвращать длительность в данных медиа.
|
||||||
|
|
||||||
|
#### Scenario: Длительность доступна
|
||||||
|
- **WHEN** видео успешно обработано
|
||||||
|
- **THEN** данные медиа содержат длительность видео
|
||||||
|
|
||||||
|
#### Scenario: Метаданные недоступны
|
||||||
|
- **WHEN** из видео не удаётся извлечь метаданные
|
||||||
|
- **THEN** запись сохраняется, а длительность пуста
|
||||||
|
|
||||||
|
### Requirement: Постер видео
|
||||||
|
Система SHALL извлекать кадр-постер и SHALL генерировать из него варианты thumb, medium и
|
||||||
|
preview тем же способом, что для изображений, чтобы сетка и обложка отображали видео постером.
|
||||||
|
|
||||||
|
#### Scenario: Генерация постера
|
||||||
|
- **WHEN** видео обработано
|
||||||
|
- **THEN** система создаёт варианты thumb, medium и preview из кадра-постера
|
||||||
|
|
||||||
|
#### Scenario: Обложка из видео
|
||||||
|
- **WHEN** видео становится обложкой альбома
|
||||||
|
- **THEN** альбом отображает постер видео
|
||||||
|
|
||||||
|
### Requirement: Гарантированное воспроизведение
|
||||||
|
Система SHALL готовить воспроизводимый вариант видео: SHALL выполнять remux без
|
||||||
|
перекодирования, когда источник web-совместим, и SHALL транскодировать в h264/yuv420p/aac
|
||||||
|
с faststart иначе; система SHALL NOT увеличивать разрешение и SHALL ограничивать длинную
|
||||||
|
сторону 1080p.
|
||||||
|
|
||||||
|
#### Scenario: Совместимый источник
|
||||||
|
- **WHEN** источник — h264/yuv420p с совместимым профилем, звуком aac или без звука, в подходящем контейнере и в пределах разрешения
|
||||||
|
- **THEN** система подготавливает вариант remux без перекодирования
|
||||||
|
|
||||||
|
#### Scenario: Несовместимый источник
|
||||||
|
- **WHEN** источник не является web-совместимым (например, hevc, 10-bit или yuv444)
|
||||||
|
- **THEN** система транскодирует видео в h264/yuv420p/aac
|
||||||
|
|
||||||
|
#### Scenario: Разрешение выше предела
|
||||||
|
- **WHEN** длинная сторона источника превышает 1080p
|
||||||
|
- **THEN** система масштабирует видео до 1080p, не увеличивая меньший источник
|
||||||
|
|
||||||
|
### Requirement: Готовность и воспроизведение видео
|
||||||
|
Данные медиа SHALL содержать адрес воспроизводимого варианта, когда он готов; клиент SHALL
|
||||||
|
воспроизводить его с перемоткой; до готовности система SHALL отдавать постер и признак
|
||||||
|
обработки, а обновление о готовности SHALL транслироваться подписчикам.
|
||||||
|
|
||||||
|
#### Scenario: Вариант не готов
|
||||||
|
- **WHEN** видео ещё обрабатывается
|
||||||
|
- **THEN** данные медиа содержат постер и не содержат адрес воспроизведения
|
||||||
|
|
||||||
|
#### Scenario: Вариант готов
|
||||||
|
- **WHEN** обработка завершена
|
||||||
|
- **THEN** данные медиа содержат адрес воспроизведения, а подписчики получают обновление
|
||||||
|
|
||||||
|
#### Scenario: Перемотка
|
||||||
|
- **WHEN** клиент перематывает воспроизведение
|
||||||
|
- **THEN** система отдаёт запрошенный диапазон байт
|
||||||
|
|
||||||
|
### Requirement: Фоновая подготовка видео
|
||||||
|
Задание подготовки видео SHALL выполняться в фоне с длительным лизингом, таймаутом и
|
||||||
|
повторами при сбое и SHALL NOT вытеснять генерацию вариантов изображений.
|
||||||
|
|
||||||
|
#### Scenario: Повтор при сбое
|
||||||
|
- **WHEN** подготовка видео завершается ошибкой
|
||||||
|
- **THEN** задание повторяется с задержкой до достижения предела попыток
|
||||||
|
|
||||||
|
#### Scenario: Изоляция от картинок
|
||||||
|
- **WHEN** длительное видео обрабатывается
|
||||||
|
- **THEN** генерация вариантов изображений продолжает выполняться
|
||||||
|
|
||||||
|
### Requirement: Оригинал видео
|
||||||
|
Система SHALL сохранять исходный видеофайл и SHALL использовать его для скачивания
|
||||||
|
независимо от подготовленного варианта.
|
||||||
|
|
||||||
|
#### Scenario: Скачивание оригинала
|
||||||
|
- **WHEN** участник скачивает видео
|
||||||
|
- **THEN** система возвращает адрес исходного файла
|
||||||
|
|
||||||
|
### Requirement: Отсутствие видео-инструментов
|
||||||
|
При отсутствии `ffmpeg`/`ffprobe` система SHALL отключать приём видео и SHALL отражать
|
||||||
|
недоступность видео-обработки в состоянии здоровья.
|
||||||
|
|
||||||
|
#### Scenario: Инструменты отсутствуют
|
||||||
|
- **WHEN** видео-инструменты недоступны
|
||||||
|
- **THEN** приём видео отклоняется, а health сообщает о недоступности видео
|
||||||
Reference in New Issue
Block a user