A premium music streaming app built with Flutter, FastAPI, Redis, and Supabase. Stream from YouTube via Invidious, manage playlists, follow friends, and play your own local music library.
# 1. Clone
git clone https://github.com/Chaganti-Reddy/resonance.git
cd resonance
# 2. Run setup (requires Docker Desktop)
.\setup.ps1
# 3. Run the app
cd musicapp
flutter pub get
flutter runWindows only: setup script requires PowerShell 5.1+ and Docker Desktop. See below for macOS/Linux.
- YouTube audio via Invidious — no API key required, 7-instance fallback pool
- Stream URLs cached in Redis (6h TTL) — minimal re-resolution
- Local music files from
./musicfolder (MP3, FLAC, OGG, M4A, AAC, WAV, OPUS) - Background playback with lock-screen controls
- Ambient color extraction — dominant color pulled from album art, animates as background tint across player and mini player (800ms smooth transition)
- Swipe to skip — swipe left/right on album art in the full player
- Floating mini player — ambient-tinted glass pill with progress bar
- Immersive full-screen player — blurred album art backdrop, glow shadow
- No dropdowns anywhere — everything uses bottom sheets or custom pickers
- Visual genre grid selection
- Artist search with Invidious autocomplete (~50ms), real-time grid filtering while typing
- Country picker with flag emojis via bottom sheet (no dropdown)
- Like songs, create and manage playlists
- Play history with play counts
- Collaborative playlists
- Follow other users
- Now Playing feed — see what friends are listening to in real time (Supabase Realtime)
- Public playlists
- Multi-signal personalised recommendations:
- Play history (30d) · liked songs · playlist songs · friend listening · onboarding prefs
- Per-artist diversity cap (max 3 songs per artist)
- Cold-start fallback for new users
| Tool | Version |
|---|---|
| Docker Desktop | 24+ |
| Flutter SDK | 3.19+ |
| Git | any |
- Create project at supabase.com
- In SQL Editor, run
supabase/schema.sql - From Project Settings → API, copy your URL and keys
setup.ps1 copies .env.example → .env. Fill in:
SUPABASE_URL=https://xxxxxxxxxxxx.supabase.co
SUPABASE_ANON_KEY=eyJhbGc...
SUPABASE_SERVICE_KEY=eyJhbGc...
SECRET_KEY=replace-with-a-long-random-stringdocker compose up -d --build
docker compose ps
curl http://localhost:8000/healthThis starts:
- resonance_backend on port
8000 - resonance_redis on port
6379
Set backend URL in musicapp/lib/core/constants/api_constants.dart:
// Android emulator
const kApiBaseUrl = 'http://10.0.2.2:8000';
// iOS simulator / web / desktop
const kApiBaseUrl = 'http://localhost:8000';Set Supabase credentials in musicapp/lib/core/constants/app_constants.dart.
┌─────────────────────────────────────────────────────────────────┐
│ Flutter App (musicapp/) │
│ Riverpod · just_audio · audio_service · palette_generator │
└────────────────────┬───────────────────────┬────────────────────┘
│ REST / HTTP │ Realtime WebSocket
▼ ▼
┌──────────────────────────┐ ┌─────────────────────────────────┐
│ FastAPI Backend │ │ Supabase │
│ (backend/) │ │ - PostgreSQL database │
│ - Invidious search │ │ - Auth (email + OAuth) │
│ - Stream URL resolution │ │ - Row Level Security │
│ - Lyrics (LRCLIB) │ │ - Realtime (now_playing) │
│ - Recommendations │ └─────────────────────────────────┘
│ - Local music scanning │
└──────────┬───────────────┘
│
▼
┌──────────────────────────┐ ┌─────────────────────────────────┐
│ Redis │ │ Invidious (open-source YouTube) │
│ - Search cache (1h TTL) │◄──│ - 7-instance fallback pool │
│ - Stream URL cache (6h) │ │ - Search + autocomplete │
│ - Artist suggestions │ │ - Audio stream extraction │
└──────────────────────────┘ └─────────────────────────────────┘
Streaming flow:
- Flutter sends
GET /api/stream?external_id=...&source=youtube - FastAPI checks Redis (6h TTL)
- On miss — Invidious resolves direct audio CDN URL across 7 instances
- URL cached, returned to Flutter
just_audiostreams directly from CDN- Flutter upserts
now_playingto Supabase → Realtime pushes to followers
| Layer | Technology |
|---|---|
| Mobile / Desktop / Web | Flutter 3 (Dart) |
| State management | Riverpod |
| Audio engine | just_audio + audio_service |
| Ambient color | palette_generator + CachedNetworkImage |
| Backend API | Python 3.11, FastAPI, Uvicorn |
| Audio source | Invidious (open-source YouTube frontend) |
| Lyrics | LRCLIB API |
| Cache | Redis 7 |
| Database | PostgreSQL via Supabase |
| Auth | Supabase Auth (email + Google OAuth) |
| Realtime | Supabase Realtime |
| Containerisation | Docker, Docker Compose |
resonance/
├── backend/
│ ├── main.py FastAPI app factory
│ ├── requirements.txt
│ ├── Dockerfile
│ └── app/
│ ├── config.py Settings (Pydantic)
│ ├── middleware/auth.py Supabase JWT verification
│ ├── models/ Pydantic response models
│ ├── routers/ API route modules
│ └── services/ Business logic
│ ├── invidious_service YouTube search + stream resolution
│ ├── music_orchestrator Search aggregation
│ ├── cache_service Redis wrapper
│ ├── lyrics_service LRCLIB integration
│ ├── radio_service Related tracks
│ └── recommendations_service Multi-signal personalisation
├── musicapp/
│ └── lib/
│ ├── main.dart
│ ├── app.dart Router + ProviderScope
│ ├── core/
│ │ ├── constants/ API URLs, app config
│ │ ├── navigation/ GoRouter setup
│ │ ├── theme/ Colors, text styles, theme
│ │ └── utils/ Extensions, formatters
│ ├── features/
│ │ ├── auth/ Login + signup
│ │ ├── onboarding/ Genre/artist/country selection
│ │ ├── home/ Feed, genres, now-playing hero
│ │ ├── player/ Full-screen player + lyrics + queue
│ │ ├── search/ Search screen
│ │ ├── library/ Liked songs + history
│ │ ├── playlist/ Playlist CRUD
│ │ ├── social/ Following feed + profiles
│ │ ├── artist/ Artist detail
│ │ ├── album/ Album detail
│ │ ├── podcasts/ Podcast browser + episodes
│ │ └── settings/ App settings + equalizer
│ └── shared/
│ ├── models/ Dart data classes
│ ├── providers/ Riverpod providers (player, auth, library, ambient color)
│ ├── services/ API client, audio, Supabase, cache
│ └── widgets/ Mini player, song tile, glass widgets
├── supabase/schema.sql DB schema + RLS policies
├── docker-compose.yml
├── setup.ps1 One-command Windows setup
└── .env.example
Swagger UI: http://localhost:8000/docs
GET /health Redis + app health
GET /api/search?q=...&source=all&limit=20 Search songs
GET /api/search/suggestions?q=... Autocomplete (Invidious)
GET /api/stream?external_id=...&source=youtube Stream URL
GET /api/artists?genre=...&country=... Artist suggestions
GET /api/lyrics?title=...&artist=... Lyrics (LRCLIB)
GET /api/radio?external_id=... Related tracks
GET /api/recommendations Personalised feed
POST /api/library/history Record play event
GET /api/library/liked Liked songs
POST /api/library/like Like a song
Drop files into ./music/ at the project root. Mounted into the container at /music.
resonance/
music/
artist - track.mp3
album/
01.flac
docker compose logs -f backend # live backend logs
docker compose restart backend # restart after .env changes
docker compose down # stop all
docker compose down -v # stop + delete Redis data
docker compose exec backend bash # shell into backend
docker compose exec redis redis-cli keys "*" # inspect cacheMIT © Chaganti-Reddy