Simple music player for Raspberry Pi
  • Go 65.6%
  • JavaScript 18.4%
  • CSS 12.5%
  • HTML 3%
  • Shell 0.5%
Find a file
2026-04-02 15:28:33 +02:00
docs docs: update hardware with ordered parts — OLED + TFT, power button, fasteners 2026-04-02 15:28:33 +02:00
internal feat: playback timeline with progress bar, elapsed/duration time display 2026-04-02 13:58:40 +02:00
scripts feat: deploy script and systemd user service 2026-04-02 12:06:22 +02:00
web feat: shuffle button on favorites to play in random order 2026-04-02 14:03:18 +02:00
.gitignore Task 1: project scaffolding 2026-04-02 11:52:22 +02:00
CLAUDE.md docs: initial project setup — design spec, implementation plan, README, and CLAUDE.md 2026-04-02 11:45:36 +02:00
go.mod fix: critical bugs from code review 2026-04-02 12:12:50 +02:00
go.sum fix: critical bugs from code review 2026-04-02 12:12:50 +02:00
main.go feat: auto-reconnect paired Bluetooth devices, fix play/pause toggle 2026-04-02 13:43:24 +02:00
mjusik.service fix: correct --cover-dir flag name in systemd service 2026-04-02 12:14:25 +02:00
README.md docs: update README to reflect actual architecture and configuration 2026-04-02 12:44:31 +02:00

mjusik

A music box for kids, built on a Raspberry Pi 4. Plays local music files over Bluetooth headsets, controlled via a web UI.

Features

  • Library scanner that indexes local music files by reading metadata from tags (via dhowden/tag and ffprobe)
  • Compilation/soundtrack albums grouped correctly by album artist
  • Album browsing with embedded cover art
  • Now playing view with play/pause, skip, repeat, and favorites
  • One favorites playlist
  • Bluetooth headset management via BlueZ D-Bus
  • Web-based remote control with live state updates over WebSocket

Architecture

+-----------------------------------------------+
|             Go binary (mjusik)                |
|                                               |
|  +----------+  +----------+  +-----------+    |
|  | Web UI   |  | Library  |  | Playback  |    |
|  | (HTTP +  |--| Scanner  |--| Engine    |    |
|  |  WS)     |  | + SQLite |  | (ffmpeg + |    |
|  +----------+  +----------+  | PipeWire) |    |
|                              +-----+-----+    |
|                                     |         |
|                          +----------+-------+ |
|                          | Bluetooth Mgmt   | |
|                          | (BlueZ D-Bus)    | |
|                          +------------------+ |
+-----------------------------------------------+
         |              |              |
    Web browser    Music files    BT headsets
                   on disk        via PipeWire

Single Go binary with four internal packages:

  • library — Recursive file scanner reads tags with dhowden/tag, uses ffprobe for multi-value fields (artist, album artist). Stores tracks, albums, and favorites in SQLite. Extracts embedded cover art to disk.
  • player — Decodes audio via an ffmpeg subprocess (any format → raw PCM). Outputs to PipeWire through the PulseAudio compatibility layer (jfreymuth/pulse). Manages queue, play/pause, skip, and repeat-one.
  • bluetooth — Talks to BlueZ over D-Bus (godbus/dbus) for device discovery, pairing, and connection. Phase 1: single adapter/headset. Phase 2: dual adapters for simultaneous playback.
  • api — HTTP server (stdlib net/http) serving a JSON API, WebSocket for live playback state (nhooyr.io/websocket), and the embedded web UI (vanilla JS via embed.FS).

Hardware

  • Raspberry Pi 4 (Debian Trixie, aarch64, headless)
  • USB Bluetooth adapter(s) for headset connectivity

Dependencies (on the Pi)

  • ffmpeg (audio decoding + tag reading via ffprobe)
  • PipeWire + WirePlumber (audio output)
  • BlueZ (Bluetooth)

No Go runtime needed — just the cross-compiled binary.

Build & Deploy

# Build and deploy in one step
bash scripts/deploy.sh musicbox

# Or manually
GOOS=linux GOARCH=arm64 go build -o mjusik .
scp mjusik musicbox:~/mjusik

The deploy script also installs a systemd user service that auto-starts on boot and restarts on failure.

Configuration

Flags (or MJUSIK_* environment variables):

Flag Env var Default Description
--music-dir MJUSIK_MUSIC_DIR /home/music Path to music files
--listen MJUSIK_LISTEN_ADDR :8080 HTTP listen address
--db MJUSIK_DB_PATH mjusik.db SQLite database path
--cover-dir MJUSIK_COVER_DIR covers Cover art cache directory