Self-hosted музыкальный сервер: Navidrome и ListenBrainz для открытия треков и построения плейлистов

Узнайте, как создать собственный музыкальный сервер с Navidrome и интегрировать ListenBrainz для отслеживания прослушиваний и формирования персональных плейлистов Discovery. Гайд для homelab и self-hosting.

Не указано

Подготовка окружения и структуры папок

Обновите систему, установите Docker и создайте директории для проекта. Это необходимо для хранения музыки, конфигов и баз данных.

# Обновление пакетов
sudo apt update && sudo apt upgrade -y

# Установка Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
newgrp docker

# Установка Docker Compose
sudo apt install docker-compose-plugin -y

# Создание структуры проекта
mkdir -p ~/music-platform/{musicdata,config,listenbrainz-data}
cd ~/music-platform

Настройка Docker Compose

Создайте файл docker-compose.yml, который определяет контейнеры Navidrome, ListenBrainz и PostgreSQL. Замените 'replace_with_strong_secret' на надежный ключ.

version: '3.8'

services:
  navidrome:
    image: deluan/navidrome:latest
    container_name: navidrome
    ports:
      - "4533:4533"
    volumes:
      - ./musicdata:/music:ro
      - ./config:/data
      - ./listenbrainz-data:/listenbrainz
    environment:
      - ND_SCANSCHEDULE=@every 1h
      - ND_LOGLEVEL=info
      - ND_BASEURL=/
      - ND_PORT=4533
      - ND_MUSICFOLDER=/music
    restart: unless-stopped
    networks:
      - music-net

  listenbrainz:
    image: metabrainz/listenbrainz:latest
    container_name: listenbrainz
    ports:
      - "8000:8000"
    volumes:
      - ./listenbrainz-data:/data
    environment:
      - LB_SECRET_KEY=replace_with_strong_secret
      - LB_DATABASE_URL=postgresql://listenbrainz:password@db/listenbrainz
    depends_on:
      - db
    restart: unless-stopped
    networks:
      - music-net

  db:
    image: postgres:14
    container_name: listenbrainz-db
    volumes:
      - ./listenbrainz-data/postgres:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=listenbrainz
      - POSTGRES_USER=listenbrainz
      - POSTGRES_PASSWORD=password
    restart: unless-stopped
    networks:
      - music-net

networks:
  music-net:
    driver: bridge

Запуск платформы

Запустите контейнеры в фоновом режиме и проверьте логи, чтобы убедиться в успешном запуске.

# Запуск контейнеров
docker compose up -d

# Проверка логов Navidrome
docker compose logs -f navidrome

# Проверка логов ListenBrainz
docker compose logs -f listenbrainz

Настройка Navidrome

Откройте http://localhost:4533, создайте администратора. Поместите музыкальные файлы в папку musicdata. Создайте конфиг navidrome.toml для точной настройки сканирования и вебхуков.

# Пример конфига config/navidrome.toml
[server]
port = 4533
address = "0.0.0.0"
scanSchedule = "@every 1h"

[auth]
jwtSecret = "your_jwt_secret_here"

[libraries]
[music]
path = "/music"
ignoreDot = true

[webhooks]
enabled = true
url = "http://your-script-host:5000/webhook"
events = ["track_played"]

Настройка ListenBrainz и интеграции

Откройте http://localhost:8000, зарегистрируйтесь и получите токен API в профиле. Для интеграции с Navidrome используйте Python-скрипт для отправки скробблов (прослушиваний) через API ListenBrainz, так как встроенного плагина нет.

# Установка зависимостей
sudo apt install python3-pip
pip3 install requests flask musicbrainzngs

# Пример скрипта scrobbler.py
import os
import json
import requests
from datetime import datetime

LB_URL = "http://localhost:8000"
LB_TOKEN = "ВАШ_ТОКЕН_ИЗ_LISTENBRAINZ"  # Получите в профиле

def send_listen(track, artist, album):
    payload = {
        "listen_type": "single",
        "payload": [{
            "listened_at": int(datetime.now().timestamp()),
            "track_metadata": {
                "track_name": track,
                "artist_name": artist,
                "release_name": album
            }
        }]
    }
    headers = {"Authorization": f"Token {LB_TOKEN}"}
    response = requests.post(f"{LB_URL}/1/submit-listens", json=payload, headers=headers)
    print(f"Status: {response.status_code}")

# Пример вызова
if __name__ == "__main__":
    send_listen("Track Name", "Artist Name", "Album Name")

Формирование рекомендаций Discovery

Используйте данные ListenBrainz для получения топ-артистов и поиска похожих через MusicBrainz API. Скрипт генерирует M3U плейлист или создает плейлист в Navidrome через Subsonic API.

import requests

LB_URL = "http://localhost:8000"
USERNAME = "ВАШ_ЮЗЕРНЕЙМ"

def get_top_artists():
    url = f"{LB_URL}/1/user/{USERNAME}/stats"
    response = requests.get(url)
    data = response.json()
    artists = data.get("artists", [])
    return [a["artist_name"] for a in artists[:10]]

def find_similar(artist):
    # Простой поиск по MusicBrainz
    mb_url = "https://musicbrainz.org/ws/2/artist/"
    params = {"query": artist, "fmt": "json"}
    headers = {"User-Agent": "music-platform/1.0"}
    response = requests.get(mb_url, params=params, headers=headers)
    # Упрощенная логика: возвращаем список условных похожих
    return [f"Similar to {artist} 1", f"Similar to {artist} 2"]

top = get_top_artists()
recommendations = []
for artist in top:
    recommendations.extend(find_similar(artist))

# Экспорт в M3U
with open("discovery_playlist.m3u", "w") as f:
    for rec in recommendations:
        f.write(f"#EXTINF:0,{rec}\n")
        f.write(f"https://your-server:4533/rest/download?u=admin&p=password&v=1.15.0&id=track_id\n")

print("Плейлист discovery_playlist.m3u создан.")

# Для создания в Navidrome используйте curl:
# curl -X POST "http://localhost:4533/rest/createPlaylist?u=admin&p=password&v=1.15.0&name=Discovery&songId=track1,track2"

Резервное копирование данных

Настройте регулярное копирование музыки и баз данных. Используйте rsync для файлов и pg_dump для PostgreSQL.

# Скрипт backup.sh
#!/bin/bash
BACKUP_DIR="/backup/music-platform"
mkdir -p $BACKUP_DIR

# Бэкап музыки
rsync -av ~/music-platform/musicdata/ $BACKUP_DIR/musicdata/

# Бэкап БД ListenBrainz
docker exec listenbrainz-db pg_dump -U listenbrainz listenbrainz > $BACKUP_DIR/listenbrainz.sql

# Архивация
tar -czf $BACKUP_DIR/backup-$(date +%Y%m%d).tar.gz $BACKUP_DIR/

# Очистка старых бэкапов (старше 7 дней)
find $BACKUP_DIR -name "backup-*.tar.gz" -mtime +7 -delete

# Добавление в cron (ежедневно в 2:00)
# 0 2 * * * ~/music-platform/backup.sh