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