Выдача чужих задач (критично). GET /api/tasks отдавал карточки ВСЕХ
пользователей вместе со ссылками и названиями, и по взятому оттуда id
любой мог забрать чужой готовый файл: неугадываемость идентификатора была
единственной защитой, а список её обнулял. Эндпоинт не использовался
фронтендом и удалён; идентификатор задачи расширен до полного uuid4.
Исчерпание потоков. Каждая задача поднимала свой поток, который до
получаса ждал на семафоре: шесть запусков в минуту с одного адреса давали
около 180 висящих потоков при TasksMax=256, то есть сервис ложился с двух
IP. Заменено очередью с постоянным пулом из трёх воркеров; переполнение
отвечает честным 503 сразу, а не молчаливым ожиданием. Проверено: число
потоков не растёт с числом задач.
Обход выбора формата. Регулярка пропускала ключевые слова селектора, и
format_id=all заставлял yt-dlp скачать все дорожки сразу. Такие слова
теперь отвергаются явно.
Переполнение диска. max_filesize у yt-dlp проверяется по Content-Length и
не работает для фрагментированных и chunked-потоков — такой поток качался
бы без ограничения. Добавлен сторож в progress hook: раз в пять секунд
проверяет накопленный размер и свободное место, прерывая задачу. Это
Proxmox-хост, заполненный раздел — авария гипервизора, а не сервиса.
Утечка внутренностей. Текст ошибки yt-dlp уходил пользователю как есть и
мог содержать локальные пути, имя пользователя и внутренние адреса.
Теперь пути и адреса вымарываются, а непредвиденные исключения наружу
показываются общим сообщением и пишутся в журнал.
Молчаливые сбои. Уборщик глушил любые исключения без единой строчки в
журнале: при потере прав на запись файлы перестали бы удаляться, диск бы
заполнился, а журнал остался бы пустым. Добавлено логирование сбоев
уборщика и ошибок загрузок (только домен, не полный URL).
Зависший индикатор. Клиент закрывал EventSource навсегда при любом
разрыве, поэтому после перезапуска сервера карточка вечно висела на
«Обработка…». Теперь переподключается, а после пяти неудач честно
сообщает о потере связи.
Скорость. Включена параллельная загрузка фрагментов: DASH-фрагменты
тянулись строго по одному, и скорость упиралась в задержку до сервера.
Замер на том же ролике: было около 8 МБ/с, стало 29 МБ/с.
Шрифты. Inter перенесён на свой сервер: запрос к Google блокировал
отрисовку и попутно отдавал им IP каждого посетителя, что противоречило
обещанию на главной. Внешних запросов со страниц не осталось.
Интерфейс. Селектор звуковой дорожки в режиме «Видео» назывался «Аудио»
так же, как отдельный режим, и создавал впечатление, что MP3 пропал.
Переименован в «Звук в видео» с пояснением, где искать MP3.
README приведён в соответствие: он утверждал, что не хранится ни ссылок,
ни адресов, хотя лента их хранит.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AwY2Cg54RK7WZdvMaLV5Di