Yay-Tsa
July 2, 2026 · View on GitHub
Self-hosted music streaming system: multi-protocol Kotlin media server + React PWA client.
Features
- Browse and stream your music library from any browser
- Progressive Web App — installable on mobile and desktop
- Karaoke mode — vocal separation powered by Meta's Demucs (optional)
- Lyrics display with time-synced scrolling
- Multi-arch images:
linux/amd64andlinux/arm64(Apple Silicon, Raspberry Pi)
Quick Start with Docker Compose
mkdir yay-tsa && cd yay-tsa
# Download configuration files
curl -O https://raw.githubusercontent.com/nikolay-e/yay-tsa/main/docker/docker-compose.yml
curl -O https://raw.githubusercontent.com/nikolay-e/yay-tsa/main/docker/example.env
cp example.env .env
# Edit .env — set MEDIA_PATH to your music library and change passwords
# Then start:
docker compose up -d
# Open http://localhost:3000
To enable karaoke (vocal separation):
docker compose --profile karaoke up -d
Upgrade to the latest version:
docker compose pull && docker compose up -d
Install with Helm (Kubernetes)
The yay-tsa-stack umbrella chart installs the whole system — PWA + backend + a
bundled Postgres/pgvector — with one command on a fresh namespace. ML, LLM, karaoke,
MPD, ingress and NetworkPolicy are all off by default.
helm repo add yay-tsa https://nikolay-e.github.io/yay-tsa
helm repo update
helm install yay-tsa yay-tsa/yay-tsa-stack \
--namespace yay-tsa --create-namespace \
--set yay-tsa-v2.backend.adminBootstrap.password=CHANGE_ME
That's it — a strong DB password is generated and preserved across upgrades, and the
first admin (admin / your password) is seeded on the empty database. Reach it with:
kubectl -n yay-tsa rollout status deploy/yay-tsa-yay-tsa-v2-backend
kubectl -n yay-tsa port-forward svc/yay-tsa 8080:80 # then open http://localhost:8080
Point it at your music and expose it publicly:
helm upgrade yay-tsa yay-tsa/yay-tsa-stack -n yay-tsa \
--reuse-values \
--set yay-tsa-v2.backend.media.enabled=true \
--set yay-tsa-v2.backend.media.existingClaim=my-music-pvc \
--set yay-tsa.ingress.enabled=true \
--set yay-tsa.ingress.hosts[0].host=music.example.com \
--set yay-tsa-v2.ingress.enabled=true \
--set yay-tsa-v2.ingress.hosts[0].host=music.example.com
media.existingClaim (a pre-created PVC) works on any/multi-node cluster; on a single node
you can use media.hostPath=/path/to/music instead. After mounting, trigger a scan:
POST /api/Admin/Library/Rescan with your admin bearer token.
TLS: the ingress examples set a host but no certificate. Terminate TLS at your ingress
(e.g. cert-manager cluster-issuer annotation + a tls: block) before exposing publicly —
login credentials and tokens travel in clear over plain HTTP.
Production / external database. Disable the bundled Postgres and point at your own
(must have the vector, pg_trgm, citext, unaccent extensions available — the app
creates them on first boot if the DB user may, e.g. an RDS/CloudSQL master user):
helm install yay-tsa yay-tsa/yay-tsa-stack -n yay-tsa --create-namespace \
--set postgresql.enabled=false \
--set externalDatabase.host=db.internal \
--set externalDatabase.user=yaytsa \
--set externalDatabase.password=... \
--set externalDatabase.database=yaytsa \
--set yay-tsa-v2.backend.adminBootstrap.password=CHANGE_ME
# (or --set externalDatabase.existingSecret=my-db-secret and
# --set global.yaytsaDatabase.secretName=my-db-secret, with the four POSTGRES_* keys)
See charts/yay-tsa-stack/values.yaml for every option.
The individual yay-tsa (PWA) and
yay-tsa-v2 (backend) charts remain available for
GitOps deployments that manage their own database.
Stack
- Frontend: React 19, Vite 8, TailwindCSS 4, React Router 7
- Backend: Kotlin 2.1, JDK 21, Spring Boot 3.4, PostgreSQL 17 (pgvector, pg_trgm, CITEXT)
- Karaoke: Python FastAPI, BS-Roformer / Hybrid Demucs
- Infrastructure: Docker, Helm, Argo CD, GitHub Actions
Structure
apps/web/ # React PWA frontend
packages/core/ # Framework-agnostic business logic
packages/platform/ # Platform-specific audio adapters
yay-tsa-v2/ # Kotlin hexagonal backend (8 bounded contexts)
services/audio-ml/ # Audio ML sidecar: stem separation (Demucs) + feature extraction (Essentia)
charts/yay-tsa-stack/ # Umbrella chart (PWA + backend + bundled Postgres) — the install entrypoint
charts/yay-tsa/ # Helm chart (PWA + audio-separator)
charts/yay-tsa-v2/ # Helm chart (backend)
charts/postgres-pgvector/ # Bundled Postgres/pgvector subchart (used by the umbrella)
docker/ # Docker Compose for self-hosting
Development
npm install && npm run dev # Frontend dev server with HMR
docker compose -f docker/docker-compose.yml up # Full stack (DB + backend + frontend)
Testing
npm run type-check # TypeScript checking
npm run format # Prettier formatting
npm test # Vitest suites (core, platform, web)
cd apps/web && npm run test:e2e # Playwright E2E
Architecture
See CLAUDE.md for detailed architecture documentation.