Files
stoat-mbot/.env.example
T
Leonid PershinandClaude Opus 5 a1596cd654 Expose the knobs that actually decide video quality
Frame size alone does not make a picture sharp: LiveKit picks a
conservative bitrate for whatever resolution it is given, so 720p could
well look worse than a well-fed 480p. The encoder ceiling and codec are
now configurable, and the frame queue's memory budget with them, since
raising the resolution multiplies both the bytes per frame and the wait.

Startup logs what the track was published with, and the README explains
which knob to move first and what in the "video sync" line says the
machine has run out of headroom.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 05:14:38 +03:00

141 lines
8.4 KiB
Bash

# ---------------------------------------------------------------- Stoat ----
# Публичный адрес API вашего инстанса (тот же, что в клиенте).
# Бот ходит по нему как обычный клиент; домен резолвится в хост через
# extra_hosts в compose.yml, поэтому TLS валидный и NAT loopback не нужен.
STOAT_API_URL=https://chat.example.com/api
# Домен вашего Stoat — тот же, что в STOAT_API_URL, без схемы.
# Используется в compose.yml: контейнер резолвит его в сам хост, где внешний
# Caddy держит валидный TLS. Сам compose.yml править не нужно.
STOAT_DOMAIN=chat.example.com
# Токен бота: Settings → My Bots → создать бота → скопировать токен.
STOAT_BOT_TOKEN=
# Префикс команд в чате.
COMMAND_PREFIX=!
# Удалять сообщение с командой после её распознавания (нужно право ManageMessages).
DELETE_COMMAND_MESSAGES=true
# Имя LiveKit-ноды из Revolt.toml, секция [hosts.livekit].
# В стандартном self-hosted это "worldwide".
VOICE_NODE=worldwide
# ------------------------------------------------------------- Веб-панель ---
PORT=3005
HOST=0.0.0.0
# Адрес, по которому панель открывается в браузере (без слэша в конце).
PUBLIC_URL=https://music.example.com
# Секрет для подписи сессионных cookie. Сгенерируйте: openssl rand -hex 32
JWT_SECRET=
# Срок жизни сессии панели, часов.
SESSION_TTL_HOURS=168
# ---------------------------------------------------------------- Аудио ----
# Путь к yt-dlp. В docker-образе он уже установлен.
YTDLP_PATH=yt-dlp
# Необязательно: cookies.txt аккаунта YouTube — снимает возрастные ограничения,
# «Sign in to confirm you're not a bot» и открывает приватные/платные видео.
# Файл должен быть доступен на ЗАПИСЬ: yt-dlp обновляет в нём ротируемые куки.
# Подробности — в README, раздел «Учётка YouTube (cookies)».
# YTDLP_COOKIES=/data/cookies.txt
# Необязательно: прокси для всех запросов yt-dlp — YouTube и SoundCloud,
# поиск, метаданные и сам аудиопоток. Пригодится, когда из сети сервера
# YouTube недоступен (Psiphon, свой SOCKS и т.п.).
# Схемы: http://, https://, socks5:// и socks5h:// (socks5h резолвит DNS на
# стороне прокси — обычно нужен именно он). Можно с логином и паролем:
# socks5h://user:pass@host:1080
# YTDLP_PROXY=socks5h://127.0.0.1:1080
# Где применять прокси: all — везде (по умолчанию), search — только поиск и
# метаданные, а сам аудиопоток качать напрямую. Второй вариант выручает, когда
# выходной IP прокси ловит от YouTube «Sign in to confirm you're not a bot»,
# а без прокси скачивание работает.
# YTDLP_PROXY_SCOPE=search
#
# Внимание: 127.0.0.1 внутри контейнера — это сам контейнер. Если прокси поднят
# на хосте, используйте socks5h://host.docker.internal:1080 и добавьте в
# compose.yml к extra_hosts строку "host.docker.internal:host-gateway".
# JS-рантайм для yt-dlp: YouTube требует исполнять свой JS, иначе извлечение
# деградирует и начинаются бот-проверки. В образе уже есть Node, поэтому по
# умолчанию используется он. Пустое значение отключает флаг.
YTDLP_JS_RUNTIME=node
# Необязательно: дополнительные --extractor-args, через ";".
# Помогает, когда YouTube не отдаёт форматы серверному IP:
# YTDLP_EXTRACTOR_ARGS=youtube:player_client=default,web_safari
# Необязательно: каталог с локальной медиатекой (смонтируйте том).
# LOCAL_MEDIA_DIR=/media/music
# Показывать клип в голосовом канале как демонстрацию экрана (только YouTube).
# Требует прав Video у бота и включённого видео в конфигурации инстанса.
# 360p по умолчанию из осторожности: кодирование видео заметно грузит CPU
# сервера. Можно поднять до 720 (VIDEO_WIDTH=1280, VIDEO_HEIGHT=720), если
# машина позволяет.
# Это лишь разрешение: сам показ включается тумблером в панели или командой
# !video, и по умолчанию выключен. При false тумблер в панели не показывается.
VIDEO_ENABLED=false
# Рамка, в которую вписывается кадр: пропорции клипа сохраняются, чёрные поля
# не добавляются. 640x360 выбрано из осторожности — видео грузит CPU.
VIDEO_WIDTH=640
VIDEO_HEIGHT=360
VIDEO_FPS=24
# Потолок битрейта кодировщика, кбит/с. 0 — оставить выбор LiveKit (он
# осторожен). Ориентиры: 360p ≈ 800, 480p ≈ 1500, 720p ≈ 2500-3500.
VIDEO_BITRATE_KBPS=0
# Кодек исходящей дорожки: auto (обычно VP8), vp8, h264, vp9, av1.
# h264 дешевле для процессора, vp9/av1 дают лучшую картинку на том же
# битрейте, но кодируются заметно дороже.
VIDEO_CODEC=auto
# Память под кадры, ожидающие своей секунды звука, МБ. Кадр 720p весит
# 1.4 МБ, 360p — 0.35 МБ, а ждать приходится несколько секунд, поэтому при
# повышении разрешения это значение нужно поднимать.
VIDEO_QUEUE_MB=64
# camera — картинка внутри плитки бота; screen — отдельной плиткой,
# как демонстрация экрана.
VIDEO_SOURCE=camera
# Подстройка синхронизации, мс. Плюс задерживает видео, минус — торопит.
# Звук и картинка публикуются двумя дорожками, поэтому идеального совпадения
# «из коробки» не гарантируется.
VIDEO_SYNC_OFFSET_MS=0
DEFAULT_VOLUME=60
MAX_QUEUE_SIZE=500
# Сколько треков максимум добавит одна ссылка на плейлист или микс.
MAX_PLAYLIST_TRACKS=100
SEARCH_RESULT_LIMIT=10
# Через сколько секунд после ухода ПОСЛЕДНЕГО человека бот покидает голосовой
# канал (0 — не выходить никогда). Пока в канале кто-то есть, бот остаётся,
# даже если очередь давно закончилась.
EMPTY_TIMEOUT_SECONDS=120
# --------------------------------------------------------------- Доступ ----
# false — управлять может любой участник сервера.
# true — только владелец, ManageServer или роль DJ_ROLE_NAME.
REQUIRE_DJ_ROLE=false
DJ_ROLE_NAME=DJ
# true — позвать бота можно только в тот голосовой канал, где вы сами находитесь
# (и панель, и команды). false — разрешить выбирать канал вручную.
REQUIRE_LISTENER=true
# ----------------------------------------------------------------- Прочее ---
LOG_LEVEL=info
NODE_ENV=production