Кружок из любого видео — и без «подпишитесь на 4 канала»

После Качалки и «Чисто» — мелочь попроще: отправить в Telegram кружок не с камеры, а из готового видео. Ботов для этого полно, и почти все устроены одинаково: прежде чем что-то сделать, просят подписаться на четыре канала, потом показывают рекламу, а кружок отдают с водяным знаком.
Задача на вечер, но раз уж все делают её с подписками — сделал без. Бот @chisto_krugi_bot: присылаешь видео — получаешь кружок. Ни подписок, ни рекламы, ни регистрации. Код открыт.
Рассказывать тут особо не о чем, поэтому коротко: что умеет и на что я всё-таки наступил.

Что умеет
Режет квадрат по центру и сжимает под Telegram: до 640×640, H.264, около 1,5 Мбит/с.
Видео длиннее минуты предлагает разрезать на кружки по минуте (до десяти) или взять одну минуту.
Нужен не тот кусок — подписываешь видео временем, например
1:20, кружок начнётся оттуда.Принимает обычное видео, файл и гифку.
Пока работает, показывает прогресс прямо в сообщении, а в конце его убирает — в чате остаётся только кружок.
Вертикальный ролик 1080×1920 на 38 секунд превращается в кружок на 1,6 МБ за 3,7 секунды на одном ядре сервера. Запись экрана 2560×1600 на 22 секунды — за 4,5 секунды, весит потом 0,6 МБ.
Весь бот — два файла на Python без зависимостей, только стандартная библиотека и FFmpeg.
Грабли №1: присланный файл может оказаться не видео
Файл присылает незнакомый человек, а FFmpeg умеет открывать не только видео. Например, плейлисты HLS: текстовый файл со ссылками на куски видео. Если переименовать такой плейлист в .mp4 и вписать в него путь к чужому файлу на сервере, FFmpeg честно пойдёт его читать и может вклеить в «кружок».
Поэтому и ffprobe, и ffmpeg запускаются с белым списком:
-protocol_whitelist file
-format_whitelist mov,mp4,matroska,webm,avi,gif,mpegts,flv,3gp,ogg
Читать можно только с диска и только обычные видеоконтейнеры. Плейлист-ловушка теперь заканчивается сообщением «Не получилось открыть файл как видео» — это проверяет отдельный тест.
Грабли №2: прогресс, который застревает на 17%
Прогресс FFmpeg отдаёт сам, если запустить его с -progress pipe:1: каждые полсекунды он пишет out_time_us=…. Я делил это время на 60 секунд — длину кружка. А видео было на 10 секунд, и полоска честно доползала до 17% и пропадала вместе с готовым кружком. Теперь делю на настоящую длину куска.
Вторая мелочь там же: ошибки FFmpeg я сначала читал из трубы. На битом видео он пишет ошибку на каждый кадр, труба переполняется — и FFmpeg замирает, ожидая, пока её прочитают. Теперь ошибки идут во временный файл, а на случай, если FFmpeg всё равно зависнет, есть таймер, который его останавливает.
Грабли №3: Telegram отдаёт ботам только 20 МБ
Чтобы сделать кружок, бот должен сначала скачать видео. Обычный Bot API отдаёт ботам файлы только до 20 МБ — а минута с телефона в 1080p весит 30–60 МБ. Обойти это можно только своим сервером Bot API (telegram-bot-api --local), тогда лимит — 2 ГБ, а файл бот берёт прямо с диска. Для Качалки такой сервер у меня уже есть, и бот это умеет. Пока работает обычный режим: видео больше 20 МБ бот просит обрезать в галерее — для кружка всё равно нужна минута.
Грабли №4: у человека закрыты видеосообщения
В настройках приватности Telegram можно запретить присылать себе голосовые и видеосообщения — и ботам тоже. Тогда на sendVideoNote Telegram отвечает ошибкой, и человек остаётся ни с чем. В этом случае бот присылает то же видео обычным файлом и подсказывает, где открыть видеосообщения.
Чтобы сервер не заметил бота
Бот живёт на том же сервере, что и Качалка. Чтобы обработка видео не отнимала у неё ресурсы, у бота свой пользователь и потолок: полтора ядра из трёх, гигабайт памяти, приоритет ниже. Разом обрабатываются два видео, у одного человека в очереди — до трёх, на человека — до 40 кружков в час.
Видео бот не хранит: сделал кружок — удалил и исходник, и результат.
Чтобы не проверять руками
44 теста. 13 — про обработку: обрезка по центру (красный и синий края должны пропасть, остаться только зелёная середина), повёрнутое видео, 60 fps, WEBM и гифка, разрезка, битые файлы, плейлист-ловушка, зависший FFmpeg. Остальные 31 — бот целиком на поддельном Telegram: от «прислал видео» до «пришёл кружок», в обычном режиме и со своим сервером Bot API. GitHub прогоняет их после каждого изменения.
Бот — @chisto_krugi_bot, исходники — github.com/kozliq/krugi. Поднять своего — python3 krugi.py и токен от BotFather.
Ещё у меня есть Качалка — сохраняет видео без водяных знаков, и «Чисто» — убирает рекламу на телефоне и компьютере. Тоже бесплатно, тоже без регистрации.
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.