https://github.com/noflowwater/yukebox
Self-hosted YouTube audio player for Bluetooth speakers
https://github.com/noflowwater/yukebox
bluetooth docker fastify music-player nextjs self-hosted typescript youtube
Last synced: 4 months ago
JSON representation
Self-hosted YouTube audio player for Bluetooth speakers
- Host: GitHub
- URL: https://github.com/noflowwater/yukebox
- Owner: noFlowWater
- License: mit
- Created: 2026-02-22T09:38:23.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-02-22T16:12:06.000Z (4 months ago)
- Last Synced: 2026-02-22T17:14:52.668Z (4 months ago)
- Topics: bluetooth, docker, fastify, music-player, nextjs, self-hosted, typescript, youtube
- Language: TypeScript
- Size: 311 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
# YukeBox
> Self-hosted YouTube audio player for Bluetooth speakers
[](LICENSE)
[](docker-compose.yml)
[](https://github.com/noFlowWater/yukebox/releases)
[](https://github.com/noFlowWater/yukebox/pkgs/container)
Search or paste a YouTube URL — YukeBox streams audio directly to your Bluetooth speaker via the web.
No cloud. No subscriptions. Just your music, your speaker, your server.
---
## Features
- **Instant Playback** — Search YouTube or paste a URL, audio starts in seconds
- **Queue Management** — Add, reorder, remove tracks with auto-advance
- **Scheduled Playback** — Set alarms or timed playlists that auto-start
- **Multi-Speaker** — Register and switch between Bluetooth speakers on the fly
- **Bluetooth Management** — Scan, pair, and connect BT speakers from the web UI with auto-reconnect
- **Favorites** — Save your favorite tracks for quick access
- **Real-time Status** — Live playback updates via Server-Sent Events
- **Multi-User Auth** — Role-based access control (Admin / User)
- **Accessibility** — Dark/light theme, text scaling, reduced motion, timezone support
- **One-Command Deploy** — Docker Compose with automated setup script
---
## Quick Start
### Prerequisites
- **Linux** (Ubuntu 22.04+, Fedora 34+, Debian 12+)
- **Docker** + Docker Compose
- **PulseAudio** or **PipeWire** (with `pipewire-pulse`)
- **Bluetooth speaker** paired and connected
### Install & Run
```bash
git clone https://github.com/noFlowWater/yukebox.git
cd yukebox
./setup.sh
```
`setup.sh` handles everything: detects your audio socket, generates secrets, pulls pre-built images from GHCR, and launches the containers.
Open **http://localhost:3000** and create your first account.
### Uninstall
```bash
./cleanup.sh # interactive
./cleanup.sh --all # remove everything
```
---
## Bluetooth Setup
YukeBox can manage Bluetooth speakers directly from the **Admin Panel** — scan for devices, pair, connect, and disconnect without touching the terminal.
1. Open the Admin Panel
2. Scroll to **Bluetooth Devices**
3. Click **Scan** to discover nearby speakers
4. Click **Pair & Connect** on any discovered device
Connected speakers are automatically registered and ready to use. Auto-reconnect handles temporary disconnections.
Alternative: CLI pairing (before running setup)
```bash
bluetoothctl scan on
bluetoothctl pair
bluetoothctl connect
bluetoothctl trust
# Verify PulseAudio sees it
pactl list sinks short
# Should show: bluez_sink.XX_XX_XX_XX_XX_XX.*
```
Or use your desktop's Bluetooth settings (GNOME Settings, KDE System Settings, etc.)
---
## Configuration
All settings live in `.env` (auto-generated by `setup.sh`):
| Variable | Default | Description |
|----------|---------|-------------|
| `PORT` | `3000` | Web UI port |
| `NODE_ENV` | `production` | Environment |
| `PULSE_SOCKET` | (auto-detected) | Host PulseAudio socket path |
| `PULSE_COOKIE` | (auto-detected) | PulseAudio cookie path |
| `JWT_SECRET` | (auto-generated) | Auth token signing key |
| `MPV_SOCKET` | `/tmp/mpv-socket` | mpv IPC socket (advanced) |
| `DB_PATH` | `/app/data/yukebox.db` | SQLite database path (advanced) |
---
## Architecture
```
┌─────────────────────────────────────────────┐
│ Browser (any device on network) │
│ http://host:3000 │
└──────────────┬──────────────────────────────┘
│
┌──────────────▼──────────────────────────────┐
│ Docker Compose │
│ ┌────────────────┐ ┌───────────────────┐ │
│ │ Frontend │ │ Backend │ │
│ │ Next.js 15 │──│ Fastify + TS │ │
│ │ shadcn/ui │ │ SQLite │ │
│ │ :3000 │ │ mpv + yt-dlp │ │
│ └────────────────┘ │ SSE streaming │ │
│ │ :4000 (internal) │ │
│ └──────┬──┬─────────┘ │
└─────────────────────────────┼──┼────────────┘
PulseAudio ───┘ └─── D-Bus (bluetoothctl)
┌─────────────────────┐
│ Bluetooth Speaker │
└─────────────────────┘
```
| Layer | Stack |
|-------|-------|
| Backend | Fastify + TypeScript (ESM) |
| Auth | JWT (jose) + httpOnly Cookie + bcryptjs |
| Database | SQLite (better-sqlite3) |
| Bluetooth | bluetoothctl via D-Bus system bus |
| Frontend | Next.js 15 + shadcn/ui |
| Real-time | Server-Sent Events (SSE) |
| Deploy | Docker Compose |
| Images | GHCR (linux/amd64, linux/arm64) |
Only port **3000** is exposed. The frontend proxies API requests internally — no CORS configuration needed.
---
## HTTPS (Optional)
For external access, use nginx as a reverse proxy. See [`nginx.example.conf`](nginx.example.conf) for a starter template.
---
## Development
```bash
# Backend (terminal 1)
cd backend && npm install && npm run dev
# Frontend (terminal 2)
cd frontend && npm install && npm run dev
```
Backend runs on `:4000`, frontend on `:3000`. Next.js rewrites proxy `/api/*` to the backend.
```bash
# Run backend tests
cd backend && npm test
```
---
## Troubleshooting
No sound from Bluetooth speaker
1. Check connection: `bluetoothctl devices Connected`
2. Check PulseAudio: `pactl list sinks short`
3. Restart audio: `systemctl --user restart pulseaudio`
"PulseAudio socket not found" during setup
- PipeWire users: install `pipewire-pulse` and restart: `systemctl --user restart pipewire-pulse`
- Verify socket: `ls ${XDG_RUNTIME_DIR}/pulse/native`
Can't connect from phone/other device
- Use `http://:3000` instead of `localhost`
- Check firewall: `sudo ufw allow 3000`
Container can't access PulseAudio
- Verify `PULSE_SOCKET` in `.env` matches your socket path
- Check audio group: your user must be in the `audio` group
---
## Contributing
Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
---
## License
[MIT](LICENSE)