music app
ongoingprivate music streaming for my inner circle. paste spotify/youtube links, auto-download, stream to friends. self-hosted on a raspberry pi.
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
- 1paste a spotify or youtube link. spotdl downloads the mp3, pulls album art and id3 tags from spotify's metadata api
- 2bull + redis queue handles downloads asynchronously. websocket gateway pushes live progress to the app, so the download progress shows in real-time
- 3library module scans the filesystem, indexes every track with its metadata, supports search by title/artist and artist grouping
- 4audio streaming uses http range requests. seeking, pause/resume, partial downloads all work natively. no buffering the whole file
- 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
- 6flutter app connects to the backend, streams audio with just_audio, shows library browser and player ui
- 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
monorepo setup. flutter + nestjs, database schema, download module with spotdl
queue system (bull + redis), spotify metadata + id3 tagging
library module, audio streaming with http range requests, websocket gateway
flutter app: api integration, spotify-inspired design overhaul
redesigned from scratch after feedback. minimal, dark, intentional.
auth system: jwt + otp, invite codes, role-based access
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.
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.