music app

ongoing

private music streaming for my inner circle. paste spotify/youtube links, auto-download, stream to friends. self-hosted on a raspberry pi.

mar 18, 2026 – nowsolo: product, full-stack, infrastructure
flutternestjsprismaredisbullwebsocketspotdlcloudflare tunnel

my own music streaming service, running on a raspberry pi in my room. paste a spotify or youtube link, it auto-downloads the mp3 with full metadata. stream to friends, invite only. curated playlists by me. no ads, no algorithm, no bs. exposed to the internet via cloudflare tunnel on a custom subdomain, so friends can stream from anywhere without me opening a single port.

how it works

  1. 1paste a spotify or youtube link. spotdl downloads the mp3, pulls album art and id3 tags from spotify's metadata api
  2. 2bull + redis queue handles downloads asynchronously. websocket gateway pushes live progress to the app, so the download progress shows in real-time
  3. 3library module scans the filesystem, indexes every track with its metadata, supports search by title/artist and artist grouping
  4. 4audio streaming uses http range requests. seeking, pause/resume, partial downloads all work natively. no buffering the whole file
  5. 5cloudflare tunnel exposes the pi to the internet securely. no port forwarding, no dynamic dns, no static ip. friends connect through a cloudflare-proxied subdomain
  6. 6flutter app connects to the backend, streams audio with just_audio, shows library browser and player ui
  7. 7analytics module: listen tracking with 30-second threshold, persona detection (night owl, early bird), streaks, weekly/all-time stats, top tracks and artists

key decisions

monorepo (flutter + nestjs in one repo)

shared types between backend and app. single git history for atomic changes. simpler ci/cd. easier when i'm the only developer.

spotdl over yt-dlp

better spotify metadata extraction. auto-fetches album art. handles playlists natively. still uses youtube as the audio source.

raspberry pi as the server

self-hosted on a pi 5 (8GB). 64GB microSD holds ~9,000 songs. cloudflare tunnel for remote access, no port forwarding, no static IP needed. perfect for 10-50 concurrent users. total cost: the pi i already had.

websocket for download progress

downloads take 10-30 seconds. polling would hammer the server. websocket pushes real-time progress. the app shows a live progress bar without any API calls.

what i built

  • nestjs backend with modular architecture: download, library, stream, queue, gateway modules
  • spotify/youtube → mp3 pipeline with spotdl, id3 tagging, and album art extraction via spotify api
  • bull + redis job queue with live websocket progress updates
  • audio streaming with http range request support: seeking, pause/resume, partial downloads
  • library scanner with metadata indexing, full-text search, and artist grouping
  • flutter mobile app with spotify-inspired design, provider state management, just_audio playback
  • raspberry pi deployment with cloudflare tunnel: secure remote access, no port forwarding
  • comprehensive test suites for stream, library, and e2e flows

what i deliberately skipped

  • no CI/CD pipelinemanual deploy from laptop. it's a personal project on a pi, not a startup.
  • no dockerruns directly on the pi. containerization adds overhead with zero benefit at this scale.
  • no monitoring or alertingno prometheus, no grafana. if it breaks, i'll notice because my music stops playing.
  • no real SMS OTPhardcoded OTP for dev. real SMS costs money and this has two users.
  • no database backupsmanual sqlite file copy. the music files are the real data, and those live on disk.

timeline

mar 18, 2026

monorepo setup. flutter + nestjs, database schema, download module with spotdl

mar 18, 2026

queue system (bull + redis), spotify metadata + id3 tagging

mar 19, 2026

library module, audio streaming with http range requests, websocket gateway

mar 19, 2026

flutter app: api integration, spotify-inspired design overhaul

redesigned from scratch after feedback. minimal, dark, intentional.

mar 20, 2026

auth system: jwt + otp, invite codes, role-based access

mar 21, 2026

switched from tailscale to cloudflare tunnel for remote access

cloudflare tunnel on a custom subdomain. no client app needed, works through any browser, and the pi stays invisible to port scanners.

mar 22, 2026

analytics module: listen tracking, persona detection, streaks, weekly stats

wanted to understand my own listening habits. 30-second threshold before a listen counts, so skips don't inflate the numbers.