# Show HN: Groovebox – self-hosted music library integrated with Discogs and Tidal

> Source: <https://github.com/danielfalbo/groovebox/>
> Published: 2026-08-21 20:37:44+00:00

## Screen.Recording.2026-08-21.at.9.32.05.PM-1.mov

A self-hosted, local-first music archival engine that consolidates physical media (Discogs collection & wantlist) and custom playlists into a single portable SQLite database with instant full-text search and a sleek mobile-first web interface.

**Backend:** Go (`net/http`

, pure standard library server)**Database:** SQLite via`modernc.org/sqlite`

(Pure Go, CGO-free, portable single binary)**Search Engine:** SQLite FTS5 (Porter stemmer + unicode61 tokenizer for instant full-text search)**Frontend:** Vanilla HTML5 + CSS3 (Glassmorphism dark mode with Blueprint BP5) + Vanilla JavaScript**Features:** Collapsible sidebar, creation date playlist sorting, 2x2 grid collage playlist covers, Library view switching (All Songs, Artists with avatars, Albums grid, Dedicated Album & Artist pages), clickable track rows navigating to Album pages, SVG cover art fallback error handling, and Discogs + Qobuz store master release search links.**Networking:** Localhost & Tailscale VPN ready

```
# Build binary
go build -o groovebox .

# Run Web Server (defaults to port 8080)
./groovebox -port 8080
./groovebox -sync-discogs
```

Access the UI locally at `http://localhost:8080`

.

`GET /api/stats`

- Total tracks, canonical albums, and playlists count.`GET /api/playlists?sort=[date_desc|date_asc|name_asc|name_desc]`

- List playlists with track counts, creation dates, and 4 cover art URLs.`POST /api/playlists`

- Create new internal playlist (`{name, description}`

).`GET /api/playlists/:id`

- Get tracks inside a specific playlist.`PUT /api/playlists/:id`

- Update playlist title and description.`DELETE /api/playlists/:id`

- Delete playlist and its track associations.`POST /api/playlists/:id/tracks`

- Add track (`{track_id}`

) to playlist.`DELETE /api/playlists/:id/tracks?position=X`

- Remove track at position`X`

from playlist.`GET /api/tracks`

- Browse all songs in the library.`POST /api/tracks`

- Add a new song to library (`{title, artist, album_title, duration_ms, spotify_id, cover_image_url}`

).`GET /api/autocomplete`

- Local database track/artist autocomplete.`GET /api/autocomplete/online`

- Live global iTunes API autocomplete for auto-filling metadata & cover art.`GET /api/artists`

- Browse all artists (aggregating albums & tracks) with cover art avatars.`GET /api/artists/:name`

- Get dedicated artist detail view with albums grid & tracks.`GET /api/albums?filter=[collection|wantlist]&q=:query`

- Browse canonical master albums. Optional filter by`collection`

(in_collection=1, owned in Discogs; sorted by most-recently-added-to-collection first) or`wantlist`

(in_wantlist=1). Optional`q`

searches title/artist.`GET /api/albums/counts`

- Get`{all, collection, wantlist}`

album counts for UI badge display.`GET /api/albums/:id`

- Get dedicated album detail view (Discogs pressings table with thumbnails & tracklist).`GET /api/search?q=:query`

- Instant FTS5 full-text search across songs, artists, and releases.`POST /api/sync/discogs`

- Trigger async Discogs collection & wantlist sync.`POST /api/albums/dedupe`

- Trigger async lossless master album deduplication (`DedupeAlbums`

), merging duplicate albums matched by Discogs master ID, normalized title, or track overlap.`GET /api/sync/status`

- Thread-safe live progress streaming (*stage*:`idle`

/`collection`

/`wantlist`

/`deduping`

/etc,*current_page*,*total_pages*,*items_fetched*,*last_synced_at*,*last_deduped_at*).

To access your music archive securely from your phone or laptop anywhere in the world without exposing ports to the public internet, deploy `groovebox`

to your Home Server via [Tailscale](https://tailscale.com).

Cross-compile a CGO-free static binary from your Mac:

```
# For Linux x86_64 server
GOOS=linux GOARCH=amd64 go build -o groovebox-linux .

# For ARM64 server / Raspberry Pi 4/5
GOOS=linux GOARCH=arm64 go build -o groovebox-arm64 .
```

Copy the executable, database, and public web assets to your home server:

```
scp groovebox-linux user@homeserver:/opt/groovebox/groovebox
scp music.db user@homeserver:/opt/groovebox/music.db
scp -r public user@homeserver:/opt/groovebox/public
```

On your home server, create `/etc/systemd/system/groovebox.service`

:

```
[Unit]
Description=Groovebox Archival System
After=network.target

[Service]
Type=simple
User=daniel
WorkingDirectory=/opt/groovebox
ExecStart=/opt/groovebox/groovebox -port 8080 -db /opt/groovebox/music.db
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
```

Enable and start the service:

```
sudo systemctl daemon-reload
sudo systemctl enable --now groovebox
```

- Ensure
**Tailscale** is running on your home server:

```
tailscale status
```

- Note your home server's Tailscale hostname or IP (e.g.
`homeserver.tail1234.ts.net`

or`100.x.y.z`

). - Open
`http://homeserver.tail1234.ts.net:8080`

or`http://100.x.y.z:8080`

from any device on your Tailnet (iPhone, Mac, iPad).

*(Optional)* Serve over HTTPS with standard port 443 using **Tailscale Serve**:

```
sudo tailscale serve --bg 8080
```

Now access securely at `https://homeserver.tail1234.ts.net`

on any device!

To visually inspect UI changes or capture layout screenshots end-to-end:

```
npx -y playwright screenshot http://localhost:8080 screenshot.png
```

: 1-to-1 canonical master release entities (`albums`

`discogs_master_id`

, title, artist, release year, cover image,`has_vinyl`

/`in_collection`

/`in_wantlist`

flags).: Specific Discogs physical pressings & digital entries (`release_versions`

`album_id`

,`discogs_release_id`

, label, cat#, format, source).: Individual songs linked to canonical albums (title, artist, duration, Spotify ID, ISRC).`tracks`

: Internal playlists.`playlists`

: Ordered track mappings.`playlist_tracks`

: FTS5 virtual table for fast searching.`search_fts`
