roman.nikolsky b5dcb7dbdc fix dockerfile
2026-07-04 02:08:06 +03:00
2026-07-04 02:08:06 +03:00
2026-07-04 01:56:10 +03:00
2026-07-04 01:56:10 +03:00
2026-07-04 02:08:06 +03:00
2026-07-04 01:56:10 +03:00
2026-07-04 01:56:10 +03:00
2026-07-04 01:56:10 +03:00
2026-07-04 01:56:10 +03:00
2026-07-04 01:56:10 +03:00
2026-07-04 01:56:10 +03:00

ytdlp-navidrome — сервис поиска и загрузки музыки

Назначение

Сервис-компаньон к Navidrome. Интерфейс — Matrix-бот. Позволяет:

  1. Искать музыку по названию трека или имени исполнителя.
  2. Отправлять превью (файл аудио) в чат для прослушивания.
  3. По подтверждению пользователя скачивать трек в коллекцию Navidrome.

Весь трафик наружу (yt-dlp и Matrix) проходит через локальный ByeByeDPI-прокси (обход DPI).

Инфраструктура: k3s на Raspberry Pi. Музыка хранится на SSD:

  • Рабочая директория (превью): /mnt/ssd/k3s/services/ytdlp_navidrome/tmp
  • Коллекция Navidrome (финальный файл): /mnt/ssd/k3s/services/navidrome/music/ytdlp

1. Архитектура

┌────────────┐                    ┌────────────────────────────────┐
│ Matrix     │   Matrix CS API    │      ytdlp-navidrome pod       │
│ homeserver │◄──────────────────►│                                │
│            │                    │  ┌────────────┐ ┌───────────┐  │
└────────────┘                    │  │ Go-сервис  │ │ ByeByeDPI │  │
                                  │  │ (Matrix    │ │ (sidecar  │  │
                                  │  │  бот +     │ │  SOCKS5   │  │
                                  │  │  yt-dlp)   │ │  прокси)  │  │
                                  │  └─────┬──────┘ └─────▲─────┘  │
                                  │        │              │ :1080   │
                                  │        │  --proxy     │         │
                                  │        └──────────────┘         │
                                  └───────────────┬────────────────┘
                                                  │
                       ┌──────────────────────────┼──────────────┐
                       │ /mnt/ssd (hostPath)      │              │
                       │                          ▼              │
                       │  ytdlp_navidrome/tmp/    navidrome/music/ytdlp/
                       │  (превью, очищается)     (финальные файлы)
                       └─────────────────────────────────────────┘

Стек

Компонент Технология Обоснование
Язык Go Статический бинарник, минимум зависимостей для ARM.
Фреймворк Echo GO Простой, быстрый
Matrix SDK mautrix-go Де-факто стандартный Go SDK для Matrix.
Поиск yt-dlp --flat-playlist --print Только метаданные, без скачивания.
Скачивание yt-dlp + ffmpeg Поддержка всех музыкальных источников.
Прокси ByeByeDPI (sidecar) Обход DPI без внешнего VPN. Локальный SOCKS5.
Хранение hostPath Общие директории с Navidrome и для превью.

Контейнеры в поде

Контейнер Образ Порты Назначение
ytdlp-bot Собственный (Go + yt-dlp + ffmpeg) Основной сервис
byedpi ghcr.io/hufrea/byedpi:latest (или собственный) 1080 (SOCKS5) Обход DPI, локальный прокси

2. Функциональные требования

2.1 Диалог с пользователем (Matrix-бот)

Пользователь общается с ботом в личном или групповом чате Matrix.

Пользователь:  /search Radiohead Creep
Бот:           Найдено 5 результатов:
               1. Radiohead - Creep (3:58)
               2. Radiohead - Creep [Live] (4:21)
               3. Radiohead - Creep [Acoustic] (3:45)
               ...
               Ответьте номером для превью.

Пользователь:  1
Бот:           [прикреплённый аудиофайл]
               Добавить в коллекцию Navidrome? (да/нет)

Пользователь:  да
Бот:           ✅ Добавлено: Radiohead - Creep.opus

Команды бота

Команда Описание
/search <запрос> Искать музыку. Возвращает список результатов с номерами.
<номер> Отправить аудиопревью трека из результатов поиска.
да / yes / добавить Сохранить трек в коллекцию Navidrome.
нет / no / отмена Отменить. Удалить превью.
/status Показать статус: место на диске, время работы, версия.
/proxy Показать текущие настройки прокси и статус ByeByeDPI.
/help Справка.

Состояние диалога

Бот хранит состояние per-user (в памяти, не персистентное в v1):

Состояние Данные
idle
search_results Запрос, список результатов, timestamp
preview_sent video_id, путь к превью-файлу, timestamp

Таймаут состояния: 10 минут. После таймаута превью удаляется из tmp/.

2.2 Поиск (внутренний)

  1. Бот формирует запрос к yt-dlp:
    yt-dlp "ytsearch{limit}:{query}" \
      --flat-playlist --print "%(id)s\t%(title)s\t%(duration_string)s\t%(channel)s" \
      --proxy socks5://byedpi:1080
    
  2. Парсит вывод, возвращает пронумерованный список.
  3. Таймаут: SEARCH_TIMEOUT (по умолчанию 10s).

2.3 Превью аудио (внутренний)

  1. Указанный трек скачивается во временную директорию:
    yt-dlp "https://www.youtube.com/watch?v={id}" \
      -x --audio-format opus --audio-quality 5 \
      --output "{tmp_dir}/{id}.%(ext)s" \
      --proxy socks5://byedpi:1080
    
    Качество 5 (среднее) — превью, сэкономить трафик и место.
  2. Бот отправляет файл в Matrix-чат как m.audio.
  3. Файл сохраняется в tmp_dir до решения пользователя (добавить / отменить).

2.4 Добавление в коллекцию (внутренний)

  1. Окончательное скачивание (или конвертация превью) в коллекцию:
    yt-dlp "https://www.youtube.com/watch?v={id}" \
      -x --audio-format opus --audio-quality 0 \
      --embed-thumbnail --add-metadata \
      --output "{music_dir}/{artist} - {title}.%(ext)s" \
      --proxy socks5://byedpi:1080
    
    Качество 0 (лучшее) — финальный файл для Navidrome.
  2. Файл переименовывается в формат <artist> - <title>.<ext>.
  3. Превью из tmp/ удаляется.
  4. Navidrome обнаружит файл при следующем сканировании (раз в 6ч).

2.5 Health check

Эндпоинт: GET /healthz (для Kubernetes liveness/readiness probes)

Ответ: 200 OK {"status": "ok"} — если:

  • Go-сервис запущен
  • yt-dlp доступен
  • ByeByeDPI sidecar отвечает (проверка через socks5://byedpi:1080)

3. Конфигурация

3.1 Переменные окружения

Matrix

Переменная Обязательная По умолчанию Описание
MATRIX_HOMESERVER да URL homeserver (например https://matrix.example.com)
MATRIX_USER_ID да @bot:example.com — ID бота
MATRIX_ACCESS_TOKEN да Access token бота
MATRIX_DEVICE_ID нет YTDLBOT Device ID
MATRIX_ENCRYPTION нет false Использовать E2EE (требует libolm/curve25519-dalek)

Поиск и скачивание

Переменная По умолчанию Описание
SEARCH_LIMIT 10 Максимум результатов поиска
SEARCH_TIMEOUT 10s Таймаут на yt-dlp search
DOWNLOAD_TIMEOUT 120s Таймаут на скачивание
AUDIO_FORMAT opus Целевой формат аудио
AUDIO_QUALITY_PREVIEW 5 Качество превью (0=лучшее, 10=худшее)
AUDIO_QUALITY_FINAL 0 Качество финального файла
PREVIEW_TTL 10m Время жизни превью-файла до автоудаления
ALLOWED_USERS Список Matrix ID через запятую (пустой = все)

Прокси (пробрасывается в yt-dlp через --proxy)

Переменная По умолчанию Описание
PROXY_ENABLED true Включить прокси для yt-dlp. false = без прокси.
PROXY_URL socks5://localhost:1080 URL прокси (SOCKS5 / HTTP). Если запущен sidecar — socks5://byedpi:1080

ByeByeDPI (sidecar-контейнер)

Параметры ByeByeDPI передаются через COMMAND в Deployment (см. §4.2).

Флаг По умолчанию (рекомендация) Описание
--ip 0.0.0.0 Адрес для прослушивания
--port 1080 Порт SOCKS5
--disorder 1-1 Fake packet для браузеров/доменов
--auto (включён) Автоматический обход DPI
--ttl 3 TTL для fake-пакетов

Все флаги настраиваются в Deployment-манифесте. Если нужен другой обходчик DPI (naiveproxy, xray, sing-box), поменяйте image и PROXY_URL.

Пути

Переменная По умолчанию Описание
MUSIC_DIR /music mountPath к коллекции Navidrome
MUSIC_SUBDIR ytdlp Поддиректория для финальных файлов
TMP_DIR /tmp/ytdlp-previews Рабочая директория для превью
YTDLP_PATH yt-dlp Путь к бинарнику

3.2 Kubernetes-манифесты

Каталог: rasp/k3s/services/ytdlp_navidrome/

├── README.md           # ← этот документ
├── main.go             # исходный код сервиса
├── Dockerfile          # мультистейдж: Go build + yt-dlp + ffmpeg
├── service.yaml        # Namespace + Deployment + PersistentVolumes
└── go.mod

Deployment — ключевые моменты

spec:
  containers:
    - name: ytdlp-bot
      image: ytdlp-navidrome:latest        # Собственный образ
      env:
        - name: MATRIX_HOMESERVER
          valueFrom:
            secretKeyRef:
              name: ytdlp-matrix-secret
              key: homeserver
        - name: MATRIX_USER_ID
          valueFrom:
            secretKeyRef:
              name: ytdlp-matrix-secret
              key: user-id
        - name: MATRIX_ACCESS_TOKEN         # секрет
          valueFrom:
            secretKeyRef:
              name: ytdlp-matrix-secret
              key: access-token
        - name: PROXY_URL
          value: "socks5://localhost:1080"   # sidecar
        - name: MUSIC_DIR
          value: "/music"
      volumeMounts:
        - name: music
          mountPath: /music/ytdlp           # коллекция (Read-Write)
        - name: tmp
          mountPath: /tmp/ytdlp-previews
      resources:
        requests: { memory: "64Mi", cpu: "50m" }
        limits:   { memory: "128Mi", cpu: "500m" }

    - name: byedpi                          # ◀ sidecar
      image: ghcr.io/hufrea/byedpi:latest
      command: ["ciadpi"]
      args:
        - "--ip=0.0.0.0"
        - "--port=1080"
        - "--auto"
        - "--disorder=1-1"
        - "--ttl=3"
      ports:
        - containerPort: 1080
          name: sock5
      resources:
        requests: { memory: "16Mi", cpu: "10m" }
        limits:   { memory: "32Mi", cpu: "100m" }
      # network=host не нужен — sidecar общается с основным
      # контейнером через localhost (shared network namespace в поде)

  volumes:
    - name: music
      hostPath:
        path: /mnt/ssd/k3s/services/navidrome/music
        type: DirectoryOrCreate
    - name: tmp
      emptyDir: { medium: Memory, sizeLimit: 512Mi }
      # Превью хранятся в tmpfs — не нагружают SSD,
      # ограничены 512 MiB для безопасности

Service: не нужен для бота (исходящие подключения к Matrix homeserver). Если нужен health endpoint для мониторинга — ClusterIP на порт 8080.

Secret:

apiVersion: v1
kind: Secret
metadata:
  name: ytdlp-matrix-secret
  namespace: ytdlp-navidrome
type: Opaque
stringData:
  homeserver: "https://matrix.example.com"
  user-id: "@bot:example.com"
  access-token: "syt_..."                  # ← ваш токен бота

4. Нефункциональные требования

4.1 Формат аудио

Параметр Превью Финальный файл
Кодек Opus Opus
Качество 5 (среднее) 0 (лучшее)
Обложка нет --embed-thumbnail
Теги минимальные --add-metadata (title, artist, album)
Пример размера ~12 МБ на трек ~35 МБ на трек

Альтернатива: MP3 V0, если клиенты не поддерживают Opus.

4.2 Именование файлов

Директория на хосте: /mnt/ssd/k3s/services/navidrome/music/ytdlp/

Формат имени: <artist> - <title>.<ext>

Примеры:

  • Radiohead - Creep.opus
  • Massive Attack - Teardrop.opus
  • unknown - dQw4w9WgXcQ.opus (метаданные неизвестны)

Запрещённые символы в имени файла (/ \ : * ? " < > |) заменяются на _.

4.3 Производительность

Метрика Целевое значение
Поиск (10 результатов) ≤ 5 секунд
Превью (1 трек) ≤ 30 секунд
Финальное скачивание (1 трек) ≤ 60 секунд
Потребление RAM (простой) ≤ 64 MiB
Потребление RAM ( ByeByeDPI ) ≤ 16 MiB
Потребление CPU (простой) ≤ 50m + 10m (bot + proxy)

4.4 Доступ из Matrix

  • Бот запускается как зарегистрированный пользователь homeserver.
  • Бот слушает события m.room.message и /search, реагирует на m.text.
  • Бот может быть ограничен ALLOWED_USERS — список Matrix ID через запятую (если пусто — отвечает всем).
  • В v1 без E2EE. E2EE поддерживается mautrix-go (опциональное включение через MATRIX_ENCRYPTION=true).

4.5 Безопасность

Вопрос Решение
Токен бота в секрете ytdlp-matrix-secret — не в env-файле кластера
Доступ к боту Опционально ALLOWED_USERS
Прокси — только для yt-dlp ByeByeDPI слушает на localhost, не проброшен наружу
Запись в коллекцию runAsUser совпадает с Navidrome (совместимость прав)

4.6 Ограничения (scope v1)

Feature Статус в v1 Примечание
Matrix-бот входит Основной интерфейс
E2EE ⚠️ опционально По флагу MATRIX_ENCRYPTION
REST API не входит Только Matrix. REST — при необходимости позже.
Web UI не входит
Групповые чаты ⚠️ basic Бот отвечает на mention в группах
Очередь загрузок не входит Синхронная загрузка
SoundCloud/Bandcamp ⚠️ best-effort yt-dlp поддерживает, поиск может не работать
Изменение прокси на лету не входит Требуется перезапуск пода

5. Логирование

Формат: текстовый, в stdout.

2026-07-02T14:30:00Z INFO  search user=@alice:example.com query="Radiohead Creep" results=10 dur=2.1s
2026-07-02T14:30:05Z INFO  preview user=@alice:example.com video_id=XF2YMYBLnSw size=1.2MB dur=18s
2026-07-02T14:30:20Z INFO  download user=@alice:example.com file="Radiohead - Creep.opus" size=3.7MB dur=12s
2026-07-02T14:30:20Z INFO  cleanup preview=XF2YMYBLnSw removed=true
2026-07-02T14:31:00Z WARN  preview_ttl_expired video_id=dQw4w9WgXcQ
2026-07-02T14:32:00Z INFO  byedpi_check status=ok latency=3ms

Уровень логирования: настраивается через LOG_LEVEL.


6. Тестирование

Уровень Что проверять
Unit Парсинг вывода yt-dlp, формирование имён файлов, санитизация, FSM состояний
Integration Запуск yt-dlp в subprocess с /dev/null прокси, проверка формата вывода
Matrix Взаимодействие с тестовым homeserver (Dendrite/Conduit)
Manual Полный сценарий: /search → номер → превью → да → файл в navidrome

7. Стадии реализации

Stage 1 — MVP

  • Matrix-бот: подключение через mautrix-go
  • Команда /search — парсинг вывода yt-dlp, отправка результатов
  • Превью: скачивание трека в tmp/, отправка аудио в чат
  • Добавление: финальное скачивание в коллекцию, очистка tmp
  • ByeByeDPI sidecar в Deployment
  • --proxy везде где yt-dlp обращается наружу
  • Dockerfile (Go + yt-dlp + ffmpeg)
  • service.yaml (Deployment + Secret)
  • Smoke-тест: /search → preview → да → файл появился в файловой системе

Stage 2 — Улучшения

  • Авторизация через ALLOWED_USERS
  • E2EE (опционально)
  • Автоочистка tmp/ по расписанию (cronJob или timer в Go)
  • /status и /proxy команды
  • Обработка ошибок: не найдено, таймаут превью, нет места
  • Батч-загрузка (серия треков по команде)

Stage 3 — Интеграция

  • Принудительное сканирование Navidrome после загрузки (Navidrome API)
  • Метрики Prometheus
  • Адаптация прокси под разные обходчики (naiveproxy, xray, sing-box)
  • REST-эндпоинты для альтернативного доступа (опционально)
S
Description
Поиск и скачивание музыки ytdlp. Интеграция с matrix bot
Readme 52 KiB
Languages
Go 97.5%
Dockerfile 2.5%