Skip to content

About

Good tool to manage your Melotrack presentation

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Мелотрек

Інструмент для проведення музичного квізу «Мелотрек»: організатори збирають програму з YouTube-посилань, програма сама завантажує відео, нарізає фрагменти й показує все на проєкторі, а ведучий керує показом з телефона. Організатори вносять команди й бали прямо в програмі, а в кінці на екрані оголошують переможців.

Як це працює

  1. Мелотрек — окрема подія (наприклад, «Мелотрек 27 вересня»). Мелотрек можна скопіювати як шаблон, і пісні та кліпи перейдуть одразу.
  2. Категорії — теми раундів, у кожній кілька пісень.
  3. Пісня — це посилання на YouTube. Можна вставити одразу кілька посилань, по одному в рядку. Після додавання:
    • назва й обкладинка підтягуються з YouTube, відповідь заповнюється як «Виконавець — Назва»;
    • відео завантажується у фоні (прогрес видно в списку);
    • фрагмент (за замовчуванням перші 15 с) нарізається автоматично. Після кожної зміни часу, рамки чи гучності він переріжеться сам, кнопка «рендер» більше не потрібна. Гучність усіх фрагментів вирівнюється (EBU R128), на початку й у кінці фрагмента звук плавно наростає і згасає.
  4. Команди організатори додають на вкладці «Команди»; їхні назви з'являються на вітальному екрані.
  5. Показ. «Екран» відкривають на комп'ютері з проєктором, «Пульт» — на телефоні. Далі все йде автоматично: назва категорії → відлік 3-2-1 → пісня → час на відповідь → наступна пісня… Після категорії показ зупиняється на екрані «Здаємо бланки / готуємо відповіді», а ведучий відкриває правильні відповіді.
  6. Оцінювання. У кожній категорії свої правила, тож перевіряльник вписує в таблицю, скільки балів команда отримала за кожну відповідь (від 0, можна дробові; порожня клітинка — ще не перевірено). Кілька людей можуть працювати одночасно. Результати глядачі бачать лише у фіналі.
  7. Фінал. Екран «Підраховуємо бали…», потім переможців оголошують по черзі: спершу всі місця нижче п'єдесталу, далі 3-тє, 2-ге і 1-ше, з конфеті.

Екран оформлюється однією з трьох тем: Неон (синтвейв), Вініл (теплий ретро-лаунж) або Сцена (концертні прожектори). Тему можна перемкнути будь-коли на вкладці «Показ».

Керування показом

Дія Пульт Клавіатура
Почати / далі велика кнопка Пробіл, →
Назад «Назад» ←
Пауза / продовжити «Пауза» P
Програти пісню ще раз «Ще раз» R
Перемотати таймер «−5 с / +5 с»
Перейти до категорії чи результатів «Перейти до…»

Показ веде сервер: усі екрани й пульти бачать один і той самий стан, а якщо телефон ведучого втратить зв'язок, екран продовжить сам. Після перезапуску сервера показ відновлюється на тому ж місці (на паузі).

Запуск у Docker (рекомендовано)

Потрібні лише Docker і Docker Compose. У образі вже є ffmpeg, yt-dlp і Deno (його потребує yt-dlp для YouTube).

cp .env.example .env      # впишіть APP_PASSWORD і JWT_SECRET
docker compose up -d --build

Сайт відкриється на http://сервер:8080. Уся база та медіа лежать у теці ./data: її й треба бекапити.

Під час кожного старту контейнер оновлює yt-dlp: YouTube регулярно ламає старі версії, і це найчастіша причина помилок завантаження. Щоб оновити вручну, просто перезапустіть контейнер: docker compose restart.

Для HTTPS поставте перед сервером будь-який reverse proxy (Caddy, nginx) і задайте SECURE_COOKIES=true. Приклад для nginx (сервер із застосунком може бути й іншою машиною, наприклад у WireGuard):

server {
    server_name melotrack.example.com;
    # listen 443 ssl; ssl_certificate … — як у решті ваших сайтів

    client_max_body_size 2g;            # ручне завантаження відео (MAX_UPLOAD_MB)

    location / {
        proxy_pass http://10.0.0.148:8080;
        proxy_set_header Host $host;    # обовʼязково: без цього WebSocket відхиляється
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_http_version 1.1;         # WebSocket (показ і живі оновлення)
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_read_timeout 1h;
        proxy_request_buffering off;    # великі файли йдуть одразу на сервер
    }
}

# у блоці http { }:
map $http_upgrade $connection_upgrade { default upgrade; '' close; }

Із SECURE_COOKIES=true увійти можна лише через HTTPS. Якщо відкривати сервер напряму за http://…:8080, сесія не збережеться. Для перевірки в локальній мережі тимчасово поставте false.

YouTube на VPS

YouTube часто блокує завантаження з IP-адрес дата-центрів: з'являється помилка «Sign in to confirm you're not a bot» або 403. Програма розпізнає ці помилки й пише в інтерфейсі, що сталося. Назви й обкладинки це не зачіпає: вони беруться з oEmbed та i.ytimg.com, які не блокуються.

Способи обійти блокування, від найпростішого:

  1. Свіжий yt-dlp. Docker-образ оновлює його сам. Якщо YouTube щойно щось змінив, увімкніть нічні збірки: YTDLP_NIGHTLY=true.
  2. Файл вручну. У вікні пісні натисніть «Замінити файлом з комп'ютера». Цей спосіб працює завжди. Файл можна скачати будь-де (наприклад, тим самим yt-dlp на своєму ноутбуці), а сервер перекодує його й наріже фрагмент. Пісні, яких немає на YouTube, додаються кнопкою «З файлу».
  3. Тунель через домашній комп'ютер (безкоштовно). Завантаження піде через домашній інтернет, який YouTube не блокує. На домашньому комп'ютері (Linux, macOS або Windows 10+ з вбудованим OpenSSH) запустіть:
    ssh -N -o ServerAliveInterval=30 -R 1080 user@ваш-vps
    Це відкриває SOCKS-проксі на 127.0.0.1:1080 на VPS. Щоб контейнер його бачив, запустіть сервіс у мережі хоста, додавши в docker-compose.yml:
    services:
      melotrack:
        network_mode: host   # замість ports:
    і в .env: YTDLP_PROXY=socks5://127.0.0.1:1080. Тунель потрібен лише тоді, коли додаєте пісні. Для стійкого з'єднання підійде autossh.
  4. Cookies акаунта YouTube. Заведіть окремий Google-акаунт і увійдіть у YouTube в приватному вікні. Експортуйте cookies у форматі Netscape (наприклад, розширенням «Get cookies.txt LOCALLY») і закрийте вікно, не виходячи з акаунта. Покладіть файл у ./data/cookies.txt і задайте YTDLP_COOKIES=/data/cookies.txt. Акаунт теоретично можуть заблокувати, тому основний не використовуйте.
  5. PO-token провайдер (експериментально, окремо не перевірявся): docker compose --profile pot up -d, а в .env:
    YTDLP_POT_PROVIDER=true
    YTDLP_EXTRA_ARGS=--extractor-args youtubepot-bgutilhttp:base_url=http://pot-provider:4416
    
  6. Платний резидентський проксі — YTDLP_PROXY=http://user:pass@host:port.

Черга завантажень і стан воркерів видно на вкладці «Показ» у блоці «Готовність».

Окремий сервер для завантаження й нарізки

Завантаження з YouTube і нарізку кліпів можна віддати іншій машині, наприклад домашньому комп'ютеру, з якого YouTube не блокує завантаження, або потужнішому серверу. Інтерфейс, база й готові відео залишаються на основному сервері. Основний сервер сам надсилає завдання воркеру, тож воркер має бути досяжним з основного сервера (наприклад, через VPN). Зворотного з'єднання не потрібно.

Завантаження й нарізка налаштовуються окремо: можна винести лише одне з них.

На машині воркера (той самий репозиторій):

cp .env.example .env    # достатньо задати WORKER_TOKEN, решта — за потреби
docker compose -f docker-compose.worker.yml up -d --build

У .env воркера:

WORKER_TOKEN=спільний_секрет_від_16_символів   # openssl rand -hex 24
WORKER_PORT=10.8.0.2:8081                      # слухати лише на VPN-адресі
# WORKER_CACHE_GB=20                           # кеш вихідних відео
# YTDLP_PROXY, YTDLP_COOKIES — як і на основному сервері

На основному сервері в .env:

WORKER_TOKEN=той_самий_секрет
DOWNLOAD_WORKER_URL=http://10.8.0.2:8081    # завантаження з YouTube
RENDER_WORKER_URL=http://10.8.0.2:8081      # нарізка кліпів (можна не задавати)

і docker compose up -d.

Як це працює:

  • воркер завантажує відео, рахує його гучність і повертає файл основному серверу. У себе він тримає копію в кеші, тому для нарізки відео вдруге не пересилається;
  • якщо нарізка на воркері, а відео додано файлом, основний сервер один раз надсилає його воркеру;
  • поки воркер недоступний, пісні чекають у черзі з позначкою «Сервер завантаження недоступний» і продовжуються самі, щойно він з'явиться;
  • стан воркерів видно на вкладці «Показ» у блоці готовності.

Без Docker воркер запускається командою melotrack worker з тими ж змінними.

Перехід зі старої версії

Під час першого запуску нова версія сама переносить дані старої:

  • перед міграцією база копіюється в <файл бази>.pre-v2.bak;
  • проєкти, категорії, пісні (з часом, обрізанням і гучністю) та фото відповідей переходять у нову схему;
  • відео з ./downloads/raw копіюються в ./data/media, а кліпи нарізаються заново автоматично. Чого немає на диску, те завантажиться знову.

Старий .env теж підходить: якщо APP_PASSWORD не задано, для входу використовується ADMIN_PASSWORD. Ролей більше немає, вхід відбувається одним паролем. Коли переконаєтесь, що все на місці, теку downloads/ можна видалити.

Розробка

Потрібні Go 1.26+, Node 24+, ffmpeg, yt-dlp і deno.

cp .env.example .env
go run ./cmd/melotrack            # API на :8080
cd frontend && npm install && npm run dev   # інтерфейс на :5173 з проксі на API

Перевірки:

go test ./internal/...
cd frontend && npm run lint && npm run build

Структура

cmd/melotrack      точка входу: конфіг, міграції, воркери, HTTP-сервер
internal/config    змінні середовища
internal/store     схема SQLite, міграції (включно з імпортом старої версії), моделі
internal/auth      вхід за паролем, сесія в HttpOnly-cookie
internal/media     yt-dlp, ffmpeg, метадані YouTube, черги завантажень і нарізки, прибирання файлів
internal/game      стан показу (чиста машина станів + сесія з таймерами)
internal/live      WebSocket-хаб: стан показу й живі оновлення для редакторів
internal/api       REST API, роздача файлів і фронтенду
frontend/src       React: project/ — редактор, show/ — екран і пульт, pages/ — сторінки

Уся фонова робота відновлюється з бази, а не з пам'яті, тож перезапуск нічого не губить. Кліп прив'язаний до налаштувань ключем (хешем часу, рамки, гучності й версії джерела), тому застарілий фрагмент видно одразу, а неактуальні файли прибираються самі.

Змінні середовища

Змінна За замовчуванням Опис
APP_PASSWORD — пароль організаторів (обов'язково)
JWT_SECRET — секрет для сесій, від 16 символів (обов'язково)
PORT, HOST 8080, 0.0.0.0 адреса сервера
DATA_DIR ./data база й медіа
DATABASE DATA_DIR/melotrack.db шлях до файлу SQLite
SESSION_TTL 168h тривалість сесії (продовжується під час роботи)
SECURE_COOKIES false true за HTTPS
CLIP_HEIGHT 720 якість кліпів: 480, 720 або 1080
DOWNLOAD_WORKERS, RENDER_WORKERS 2, 1 паралельність
MAX_UPLOAD_MB 2048 ліміт ручного завантаження
YTDLP_PROXY — проксі для YouTube
YTDLP_COOKIES — шлях до cookies.txt
YTDLP_EXTRA_ARGS — додаткові аргументи yt-dlp
YTDLP_AUTO_UPDATE true (Docker) оновлювати yt-dlp під час старту
YTDLP_NIGHTLY false (Docker) нічні збірки yt-dlp
DOWNLOAD_WORKER_URL — адреса воркера для завантажень (порожньо — на цьому сервері)
RENDER_WORKER_URL — адреса воркера для нарізки (порожньо — на цьому сервері)
WORKER_TOKEN — спільний секрет основного сервера й воркера, від 16 символів
WORKER_LISTEN 0.0.0.0:8081 (воркер) адреса, на якій він слухає
WORKER_NAME ім'я хоста (воркер) назва, яку видно в інтерфейсі
WORKER_CACHE_GB 20 (воркер) розмір кешу вихідних відео
ALLOWED_ORIGINS http://localhost:5173 додаткові origin-и для WebSocket (dev-сервер)

About

Good tool to manage your Melotrack presentation

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages