Media server for organizing and streaming music and podcasts with partial support for OpenSubsonic-compatible clients. Built with PHP 8.5 and Symfony 8.1, using MariaDB for persistence, Valkey for caching/locking, and Symfony Messenger with LavinMQ for background processing. Docker/Podman and FrankenPHP provide the runtime.
  • PHP 99.8%
  • Dockerfile 0.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Nico Moehring 197c3d0d39 Publication
2026-10-20 11:27:02 +02:00
.devcontainer Publication 2026-10-20 11:27:02 +02:00
.idea Publication 2026-10-20 11:27:02 +02:00
bin Publication 2026-10-20 11:27:02 +02:00
config Publication 2026-10-20 11:27:02 +02:00
docker Publication 2026-10-20 11:27:02 +02:00
docs Publication 2026-10-20 11:27:02 +02:00
migrations Publication 2026-10-20 11:27:02 +02:00
public Publication 2026-10-20 11:27:02 +02:00
src Publication 2026-10-20 11:27:02 +02:00
tests Publication 2026-10-20 11:27:02 +02:00
.dockerignore Publication 2026-10-20 11:27:02 +02:00
.editorconfig Publication 2026-10-20 11:27:02 +02:00
.env Publication 2026-10-20 11:27:02 +02:00
.env.dev Publication 2026-10-20 11:27:02 +02:00
.env.docker Publication 2026-10-20 11:27:02 +02:00
.env.docker.local.example Publication 2026-10-20 11:27:02 +02:00
.env.test Publication 2026-10-20 11:27:02 +02:00
.gitignore Publication 2026-10-20 11:27:02 +02:00
.php-cs-fixer.dist.php Publication 2026-10-20 11:27:02 +02:00
AGENTS.md Publication 2026-10-20 11:27:02 +02:00
composer.json Publication 2026-10-20 11:27:02 +02:00
composer.lock Publication 2026-10-20 11:27:02 +02:00
deptrac.yaml Publication 2026-10-20 11:27:02 +02:00
infection.json5 Publication 2026-10-20 11:27:02 +02:00
php.ini Publication 2026-10-20 11:27:02 +02:00
phpstan.dist.neon Publication 2026-10-20 11:27:02 +02:00
phpunit.dist.xml Publication 2026-10-20 11:27:02 +02:00
README.md Publication 2026-10-20 11:27:02 +02:00
symfony.lock Publication 2026-10-20 11:27:02 +02:00

SymfonyAudioBackend

This project is an audio library backend for managing and streaming music, playlists, podcasts, and background sounds. It handles audio uploads, metadata extraction, Opus compression, podcast downloads, and artwork generation.

This server is meant to be used with a dedicated administration application for managing the media on the server and with OpenSubsonic-compatible clients (e.g., Feishin, Tempus, Symfonium) for consuming the media.

Technologies

Area Main technologies
Application PHP 8.5+, Symfony 8.1, Composer
Persistence Doctrine ORM 3, Doctrine Migrations, MariaDB 12
Background work Symfony Messenger and Scheduler, LavinMQ message queues
Caching and coordination Valkey 9, Symfony Cache and Lock
API contracts Symfony Serializer, ObjectMapper, and Validator; NelmioApiDocBundle and swagger-php for OpenAPI documentation
Media processing FFmpeg for Opus compression, ImageMagick for thumbnails, PHP parsers for FLAC and Opus metadata
External systems MusicBrainz and Cover Art Archive for release information and artwork; podcast RSS feeds; optional LocalAI or OpenAI image generation through Symfony AI
Runtime and development Docker/Podman Compose, devcontainers; FrankenPHP and Caddy in the production stack

Application architecture

The application is internally split into multiple layers with distinct responsibilities.

Layer Responsibility
Controller Controllers expose HTTP endpoints. Each endpoint triggers an application process or returns data from a DisplayRepository
DisplayRepository DisplayRepositories provide read-only access to the database and return the data as use-case specific DTOs.
Process Processes represent, usually multi-step, operations that change the application state. Process classes use Services and Repositories in order to carry out a specific task while coordinating database transactions and external locks.
Service Services provide functions to change the application state or access external systems. Services are only responsible for providing an abstract interface to the system behind them.
Repository Repositories provide read-write access to the database and return data as Doctrine entities.
MessageHandler Message handlers process messages from the MessageQueue and trigger application processes.
EventListener Event listeners react to domain events and trigger synchronous or asynchronous actions via the MessageQueue or the Services.
Utility Utility classes provide reusable functions to the rest of the application. Utilities never change the state of the application.

The application uses multiple worker processes to handle async tasks. Multiple queues are used to avoid that short-running tasks (e.g., processing the outbox, removing old files) are blocked by long-running tasks (e.g., compressing media files, updating podcasts and thumbnails).

Worker Purpose
Async Processes messages that can be processed quickly (e.g. processing the outbox, removing old files)
Compression Converts media files to OPUS files.
Podcast Updates the stored podcasts by checking their current RSS feeds, downloading new episodes and clean-up old episodes.
Thumbnail Generates thumbnails for entities (album, artist, genre, playlist).

The documentation index contains architecture and data-model diagrams, plus guides to individual processes.

The API of the application is split into two parts:

  • The /api endpoints serve the dedicated administration application.
  • The /rest endpoints provide partial OpenSubsonic compatibility for audio clients.

See the API guide for supported endpoints and compatibility limitations.

Code quality and testing tools

The project uses the following tools to ensure correctness, code quality, and coding style consistency:

Tool Purpose
PHPUnit Automated tests
Infection Mutation testing
PHPStan Static analysis
Deptrac Architecture dependency checks
PHP-CS-Fixer Automated formatting
NelmioApiDocBundle API documentation
SPX Request profiling

Development with devcontainers

The application was developed using devcontainers to provide a reproducible development environment. The devcontainer provides an environment with all required PHP dependencies and external systems (e.g., MariaDB, Valkey, LavinMQ).

To use the devcontainer, Docker or Podman as well as a compatible IDE (e.g. PHPStorm, VSCode) are required.

The provided devcontainer configuration was tested with PHPStorm and Podman. Different environments might require changes to the configuration.

If the provided devcontainer configuration was used to load this project, the following steps have to be executed inside the container to run the application:

  1. Install Composer dependencies
composer install
  1. Run the migrations
php bin/console doctrine:migrations:migrate --no-interaction
  1. Run the development server
composer run dev
  1. Run the background worker
php bin/console messenger:consume async compression podcast thumbnail scheduler_default

The API is available at http://localhost:8000 through the forwarded port.

The application is able to generate thumbnails for artists, genres and playlists with AI. This option is disabled by default. It can be enabled by setting the environment variable APP_AI_GENERATE_THUMBNAILS to true in .env.dev.local. The thumbnails can be generated either by a LocalAI instance or through OpenAI.

To enable local generation, the variable APP_AI_USE_LOCAL_AI has to be set to true and the variable APP_LOCALAI_BASE_URL has to be set to the URL of the LocalAI instance. The LocalAI instance has to have the model qwen-image-2.1-q4_k-ggml available.

To use OpenAI for thumbnail generation, a valid OpenAI API key has to be provided in the variable APP_OPENAI_API_KEY in .env.dev.local.

Production setup with Docker/Podman compose

The application is designed to be run with Docker or Podman compose. The included "compose.yaml" contains all the necessary services to run the application.

The steps required to set up the docker/podman environment are documented in the docker README.

AI-assisted development

The OpenSubsonic endpoints, OpenAPI documentation, and audio file parsing logic were implemented using an AI-assisted workflow.