Playing with video only worked for clips YouTube still serves as a single progressive file, and it mostly does not: the log showed "Requested format is not available" and every track fell back to sound only. A progressive format is still preferred when offered — one download, one decode — but when there is none, video and audio are fetched in parallel and handed to one ffmpeg over separate pipes, which pairs them by timestamp. This also lifts the 360p ceiling: the height is now a CPU choice rather than a limit. The extra-descriptor plumbing (two inputs, two outputs on one ffmpeg) was verified against synthetic media: exactly 5.0s of PCM and 120 whole frames at 24 fps, no partial tail. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
115 lines
6.7 KiB
Bash
115 lines
6.7 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
|
|
VIDEO_WIDTH=640
|
|
VIDEO_HEIGHT=360
|
|
VIDEO_FPS=24
|
|
|
|
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
|