|
All checks were successful
Build and publish Docker image / build-push-package (push) Has been skipped
|
||
|---|---|---|
| .forgejo/workflows | ||
| [ReleaseNotes] | ||
| Deployment | ||
| Docs | ||
| experiments/musicfm | ||
| Scripts | ||
| src/MediaPlayerZ | ||
| tests | ||
| .codevalidator-ignore.json | ||
| .codevalidator.json | ||
| .dockerignore | ||
| .editorconfig | ||
| .env.example | ||
| .gitattributes | ||
| .gitignore | ||
| AGENTS.md | ||
| docker-compose.test.yml | ||
| docker-compose.yml | ||
| Dockerfile | ||
| dotnet-tools.json | ||
| global.json | ||
| MediaPlayerZ.sln | ||
| README.md | ||
MediaPlayerZ
Музыкальный веб-плеер на C# / .NET 10 и Blazor Web App с глобальным Interactive Server. Медиатека читается с диска, плейлисты хранятся в SQLite через Entity Framework. Аутентификации нет.
Быстрый запуск
Требуются .NET SDK 10.0, Git LFS и Docker Desktop для отдельного контейнера FFmpeg.
global.json разрешает актуальные feature bands этой версии. Профиль разработки
использует предоставленную медиатеку testAudio.
git lfs pull
$env:TEST_MEDIA_PATH = Join-Path $PWD 'testAudio'
$env:TEST_CACHE_PATH = Join-Path $PWD 'Cache'
New-Item -ItemType Directory -Force $env:TEST_CACHE_PATH | Out-Null
docker compose -f docker-compose.test.yml --profile test up -d ffmpeg-test
dotnet build .\MediaPlayerZ.sln
dotnet run --project .\src\MediaPlayerZ\MediaPlayerZ.csproj --launch-profile http
Приложение: http://localhost:5082/. Живость процесса: http://localhost:5082/health. Готовность медиатеки: http://localhost:5082/ready. Первый запуск показывает прогресс индексации; повторный использует сохранённые метаданные, превью и признаки MusicFM. Модель ONNX поставляется через Git LFS и занимает около 782 MB. При старте приложение функционально проверяет GPU: Windows использует DirectML, Linux — доступный CUDA runtime; при неуспешной проверке весь текущий процесс работает на CPU без повторных GPU-попыток. На первом проходе вычисление признаков может занять заметное время; прогресс показывает обработанные треки и фрагменты. Полный Python-стенд для запуска приложения не требуется.
Возможности
- Плейлисты в SQLite, выбор вложенных папок и треков в ленивом дереве.
- Альбомы FLAC и других поддерживаемых форматов с внешним CUE: отдельные дорожки, их названия, длительности, превью и рекомендации без физической нарезки оригинала.
- Серверный поиск, группировка по папкам и виртуальная загрузка списка.
- Прямое воспроизведение с Range, AAC/HLS для несовместимого аудио, перемотка, история Next/Previous и shuffle без повторов в текущем проходе.
- Отдельный случайный проход всей медиатеки, включая музыку вне плейлистов.
- Полный список медиатеки, закреплённое избранное и отметки сердцем.
- Подбор похожих треков по фрагментам MusicFM и «Подбери мне...» по общей карте избранного с усилением часто встречающихся направлений.
- Тексты LRCLIB в SQLite: правая выезжающая панель, сохранённые LRC-тайминги, подсветка текущих строк и прокрутка вслед за воспроизведением.
- Редактирование плейлистов, контекстные меню и сохранение порядка перетаскиванием.
- Нижняя панель с обложкой и живым спектром, верхней шкалой перемотки и всплывающей громкостью.
- Повтор полного плейлиста, включая shuffle, и прокручиваемый редактор выбора музыки.
- Обложки, анимированные WebP-превью и живая волна Web Audio/Canvas из viewer.
- Независимые очереди вкладок, отменяемый FFmpeg, повторное использование кэша.
- Централизованная локализация EN/RU по языку браузера, английский fallback.
- Утверждённая тёмная палитра и локальный шрифт Material Icons.
- Dockerfile для .NET 10, Compose и Forgejo pipeline публикации образа.
- Правила разработки и проверки в AGENTS.md.
Продовый docker-compose.yml содержит отдельные пути музыки на HDD
(D:\Jellyfin Media\Music) и кэша/БД на M.2 (C:\MediaPlayerZ\Cache, C:\MediaPlayerZ\Db).
Compose запускает два контейнера: приложение на .NET и отдельный ffmpeg-universal.
Приложение выполняет команды во втором контейнере через локальный Docker socket.
Музыка подключается к обоим только для чтения, кэш общий, БД доступна только приложению.
Доступ к Docker socket даёт приложению права управления Docker хоста; подробности
настройки — в Docs/Run.md.
Отдельный docker-compose.test.yml запускает профиль test
с тестовой музыкой и изолированными записываемыми каталогами.
GPU в тестовом контейнере
Тестовый Compose передаёт все доступные NVIDIA GPU сервису mediaplayerz-test
через gpus: all; продовый docker-compose.yml намеренно не запрашивает GPU.
Для тестовой сборки выбран Docker-target gpu-final, который добавляет необходимые
ONNX Runtime библиотеки CUDA 12 и cuDNN 9. Обычный target final остаётся без них.
Нужны Docker Compose 2.30 или новее и работающий NVIDIA runtime: в Linux установите
NVIDIA Container Toolkit, а в Docker Desktop для Windows включите WSL 2 backend
и GPU support. Доступ Docker к видеокарте можно проверить до запуска приложения:
docker run --rm --gpus all nvidia/cuda:12.8.1-cudnn-runtime-ubuntu24.04 nvidia-smi
После успешной проверки запустите тестовое окружение обычной командой:
New-Item -ItemType Directory -Force artifacts\docker-test\Db, artifacts\docker-test\Cache
docker compose -f docker-compose.test.yml --profile test up -d --build
docker compose -f docker-compose.test.yml logs mediaplayerz-test
В журнале успешный выбор выглядит как selected Gpu through CUDAExecutionProvider,
а на экране индексации отображается GPU. Если GPU-тест не нужен или NVIDIA runtime
на машине отсутствует, удалите либо переопределите gpus: all в локальном Compose override;
после запуска без GPU приложение автоматически использует CPU.
Получение MusicFM-эмбеддингов при индексации можно полностью отключить в .env:
MEDIAPLAYERZ_EMBEDDINGS_ENABLED=false
Оба Compose-файла передают значение как Embeddings__Enabled. При false приложение
не выполняет startup-probe, не загружает ONNX-модель и не создаёт новые эмбеддинги;
остальные этапы индексации продолжают работать, а уже сохранённые признаки не удаляются.
Несколько папок медиатеки
Основной docker-compose.yml намеренно не изменён. Для тестового окружения скрипт
Scripts/Generate-TestMediaOverride.ps1 принимает массив любого размера и создаёт
Compose override с парными read-only подключениями для приложения и FFmpeg. Имена
папок верхнего уровня строятся из имён исходных каталогов; совпадения автоматически
получают числовой суффикс.
$mediaPaths = @(
"D:\Music",
"E:\Audio",
"F:\Archive\Lossless"
)
.\Scripts\Generate-TestMediaOverride.ps1 -MediaPath $mediaPaths
docker compose `
-f docker-compose.test.yml `
-f artifacts/docker-test/docker-compose.media.generated.yml `
--profile test up -d --build
Количество путей не ограничено заранее. Каждый каталог должен существовать и иметь
уникальный итоговый путь. Сгенерированный файл находится в игнорируемом каталоге
artifacts/docker-test, поэтому локальные пути не попадут в Git. Чтобы задать удобные
отображаемые имена вручную, передайте массив той же длины:
.\Scripts\Generate-TestMediaOverride.ps1 `
-MediaPath @("D:\Music", "E:\Audio") `
-RootName @("Drive-D", "Drive-E")
Повторный запуск генератора безопасно заменяет предыдущий override. Без него тестовый
Compose по-прежнему использует один каталог TEST_MEDIA_PATH как корень медиатеки.
Альбомы с CUE автоматически разворачиваются при индексации. Подробности формата, обновления существующей коллекции и воспроизведения — в Docs/Cue.md.
Тексты песен
Оба compose-файла поддерживают отдельный SOCKS5-прокси для LRCLIB:
LRCLIB_PROXY_ADDRESS, LRCLIB_PROXY_PORT, LRCLIB_PROXY_USERNAME,
LRCLIB_PROXY_PASSWORD. Значения задаются в .env по образцу .env.example.
Пустой адрес означает прямой запрос; при заданном адресе обхода прокси нет.
Настройка и пример — в Docs/Run.md.
При индексации новые треки и записи без текста проверяются в LRCLIB.
Название берётся из музыкальных тегов; имя файла используется только при их отсутствии.
Запросы идут последовательно, с паузой не менее секунды. Для загрузки нужен доступ
к https://lrclib.net/; ключ API не требуется. Найденные тексты сохраняются в БД,
отказ внешнего сервиса не мешает воспроизведению, а пропуски проверяются при следующей индексации.
Кнопка текста находится слева от подбора похожих треков и доступна только при наличии слов. В шапке панели — название и группа, закрытие — крестиком, Escape или повторным нажатием кнопки. Текст без таймингов отображается без подсветки; LRC следует за воспроизведением и перемоткой. После ручной прокрутки автоматическое следование приостанавливается на 5 секунд.
Качество воспроизведения
Совместимый с браузером файл воспроизводится напрямую, с исходными характеристиками. При конвертации используется AAC-LC, стерео, HLS с сегментами MPEG-TS примерно по 2 секунды. Битрейт и частота берутся из исходной аудиодорожки и ограничиваются возможностями AAC и браузера. Например, 128 kbit/s / 44,1 kHz сохраняются при поддержке этого режима. Частота снижается только при необходимости совместимости. Нормализация громкости для воспроизведения не применяется. Mono 24 kHz, нормализация и окна до 30 секунд с перекрытием 2 секунды относятся к подготовке признаков MusicFM.
Документация
- План реализации.
- Запуск, проверки и Docker/Forgejo.
- Структура проекта.
- Результаты проверок и ограничения среды.
- Сторонние материалы.
- Исходная заметка о проекте.
- Python-стенд MusicFM: индексация и два эксперимента подбора музыки.
- Поставляемая модель ONNX: Git LFS и контракт C#.
Репозиторий: ssh://git@git.zaharatot.ru:222/Zaharatot/MediaPlayerZ.git. Основная ветка: main.