No description
Find a file
maksimenko 6800dedfd7
All checks were successful
Build and publish Docker image / build-push-package (push) Has been skipped
Релизноут
2026-09-17 21:47:31 +03:00
.forgejo/workflows [BUILD] Initial commit: MediaPlayerZ с отдельным контейнером FFmpeg 2026-09-13 14:16:00 +03:00
[ReleaseNotes] Релизноут 2026-09-17 21:47:31 +03:00
Deployment [BUILD] Initial commit: MediaPlayerZ с отдельным контейнером FFmpeg 2026-09-13 14:16:00 +03:00
Docs [BUILD] Improve indexing, recommendations, and playback 2026-09-17 21:45:34 +03:00
experiments/musicfm [BUILD] Initial commit: MediaPlayerZ с отдельным контейнером FFmpeg 2026-09-13 14:16:00 +03:00
Scripts [BUILD] Improve indexing, recommendations, and playback 2026-09-17 21:45:34 +03:00
src/MediaPlayerZ [BUILD] Improve indexing, recommendations, and playback 2026-09-17 21:45:34 +03:00
tests [BUILD] Improve indexing, recommendations, and playback 2026-09-17 21:45:34 +03:00
.codevalidator-ignore.json [BUILD] Improve indexing, recommendations, and playback 2026-09-17 21:45:34 +03:00
.codevalidator.json [BUILD] Initial commit: MediaPlayerZ с отдельным контейнером FFmpeg 2026-09-13 14:16:00 +03:00
.dockerignore [BUILD] Initial commit: MediaPlayerZ с отдельным контейнером FFmpeg 2026-09-13 14:16:00 +03:00
.editorconfig [BUILD] Initial commit: MediaPlayerZ с отдельным контейнером FFmpeg 2026-09-13 14:16:00 +03:00
.env.example [BUILD] Improve indexing, recommendations, and playback 2026-09-17 21:45:34 +03:00
.gitattributes [BUILD] Initial commit: MediaPlayerZ с отдельным контейнером FFmpeg 2026-09-13 14:16:00 +03:00
.gitignore [BUILD] Initial commit: MediaPlayerZ с отдельным контейнером FFmpeg 2026-09-13 14:16:00 +03:00
AGENTS.md [BUILD] Initial commit: MediaPlayerZ с отдельным контейнером FFmpeg 2026-09-13 14:16:00 +03:00
docker-compose.test.yml [BUILD] Improve indexing, recommendations, and playback 2026-09-17 21:45:34 +03:00
docker-compose.yml [BUILD] Improve indexing, recommendations, and playback 2026-09-17 21:45:34 +03:00
Dockerfile [BUILD] Improve indexing, recommendations, and playback 2026-09-17 21:45:34 +03:00
dotnet-tools.json [BUILD] Initial commit: MediaPlayerZ с отдельным контейнером FFmpeg 2026-09-13 14:16:00 +03:00
global.json [BUILD] Initial commit: MediaPlayerZ с отдельным контейнером FFmpeg 2026-09-13 14:16:00 +03:00
MediaPlayerZ.sln [BUILD] Initial commit: MediaPlayerZ с отдельным контейнером FFmpeg 2026-09-13 14:16:00 +03:00
README.md [BUILD] Improve indexing, recommendations, and playback 2026-09-17 21:45:34 +03:00

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.

Документация

Репозиторий: ssh://git@git.zaharatot.ru:222/Zaharatot/MediaPlayerZ.git. Основная ветка: main.