commit 52ecba7d3f78afa8f6c54178f957b9a7ccd7d459 Author: Jarian Cottingham Date: Fri Jul 3 01:06:35 2026 +0000 initial commit diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..2d3a7d2 --- /dev/null +++ b/.env.example @@ -0,0 +1,20 @@ +# Backend +DATABASE_URL=sqlite:///./app.db +MUSIC_DIR=./music +UPLOAD_DIR=./uploads +STATIC_DIR=./static +TRANSCODE_FORMAT=ogg +TRANSCODE_BITRATE=192k + +# APIs +GENIUS_API_KEY=your_genius_api_key +RADIO_BROWSER_INSTANCE=https://de1.api.radio-browser.info +MUSICBRAINZ_USER_AGENT=MusicApp/1.0 + +# Server +BACKEND_HOST=0.0.0.0 +BACKEND_PORT=8000 +CORS_ORIGINS=http://localhost:5173,http://localhost:8081 + +# LoFi Streams +LOFI_GIRL_URL=https://www.youtube.com/live/jfKfPfyJRdk \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9b7993a --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +node_modules/ +dist/ +build/ +.env +*.pyc +__pycache__/ +*.log +.DS_Store +coverage/ +.typed/ +expo/ +ios/ +android/ +*.jks +*.p12 +keystore.* +upload-key.keystore +api-key.json +*.o +*.whl +music/* +uploads/* +static/* +backend/app.db \ No newline at end of file diff --git a/PLAN.md b/PLAN.md new file mode 100644 index 0000000..8ad1386 --- /dev/null +++ b/PLAN.md @@ -0,0 +1,618 @@ +# Music App — Comprehensive Implementation Plan + +## Progress — COMPLETE ✅ + +| Phase | Status | Details | +|---|---|---| +| Phase 1: Foundation | ✅ | Monorepo, shared types, backend scaffold, web/mobile apps, Docker | +| Phase 2: Core Music | ✅ | Audio pipeline, streaming, upload, scanning, metadata, transcoding | +| Phase 3: Core Pages | ✅ | 12 pages, vinyl components, playback controls, API wiring | +| Phase 4: Discovery | ✅ | Mood Radio, Internet Radio, New Releases, LoFi Channels | +| Phase 5: Social | ✅ | SharePlay, Collab, Account page, playlist sharing | +| Phase 6: Polish | ✅ | Framer Motion animations, responsive CSS, accessibility, testing | +| Phase 7: Extras | ✅ | Live Events placeholder, final polish | + +### Test Results + +| Suite | Passing | Status | +|---|---|---| +| Backend Endpoints | 75/75 | ✅ 100% | +| Backend Unit Tests | 38/38 | ✅ 100% | +| Web TypeScript | 0 errors | ✅ Clean | +| Playwright E2E | Written (4 spec files, 30+ tests) | 📝 Ready to run | + +### Project Stats + +**Total Files**: 121 (26 web, 46 backend, 19 shared, 16 mobile, 4 e2e, 2 backend tests, 8 config) + +### How to Run + +```bash +# Backend +cd backend && source venv/bin/activate && python -m uvicorn app.main:app --reload --port 8000 + +# Web +cd web && npm run dev + +# Both (Docker) +docker-compose up + +# Tests +cd backend && python tests/test_endpoints.py # endpoint tests +cd backend && python -m pytest tests/test_services.py -v # unit tests +npx playwright test # e2e (requires web server running) +``` + +## 1. Tech Stack + +| Layer | Technology | +|---|---| +| **Web Frontend** | React + TypeScript + Vite | +| **Web UI** | Radix UI (headless primitives) + Tailwind CSS + Framer Motion (animations) | +| **Mobile Frontend** | React Native + Expo | +| **Mobile UI** | NativeWind (Tailwind) + custom components | +| **Shared Code** | Separate `shared/` workspace package (types, API client, utils) | +| **Backend** | Python 3.11 + FastAPI | +| **Database** | SQLite + SQLAlchemy ORM | +| **Real-time** | WebSockets (`fastapi-websocket`) | +| **Audio** | MP3, AAC, FLAC, WAV, OGG (transcoded to OGG for streaming) | +| **Lyrics** | Genius API | +| **Internet Radio** | RadioBrowser API | +| **New Releases** | MusicBrainz API (check library artists for new releases) | +| **Mood Analysis** | Keyword/mood scoring on lyrics → 10 mood categories | +| **Auth** | None for v1 (single-user mode) | +| **Containerization** | Docker + Docker Compose | + +## 2. Project Structure + +``` +music-app/ +├── package.json # Monorepo root (npm workspaces) +├── shared/ # Shared package (workspace) +│ ├── src/ +│ │ ├── types/ # TypeScript interfaces (Song, Playlist, Mood, etc.) +│ │ ├── api/ # API client (fetch wrapper, endpoints) +│ │ └── constants/ # Mood categories, nav items, etc. +│ └── package.json +├── web/ # React web app +│ ├── src/ +│ │ ├── app/ # App router, layout, global state +│ │ ├── components/ +│ │ │ ├── common/ # Button, Icon, Badge, etc. +│ │ │ ├── navigation/ # NavHub, BottomNavBar, NowPlayingMiniBar +│ │ │ ├── vinyl/ # VinylStack, VinylRecord, VinylSleeve +│ │ │ ├── player/ # ProgressBar, PlaybackControls, OverlaySeek +│ │ │ └── visual/ # MoodBackground, AlbumArt, etc. +│ │ ├── pages/ # 12 page components +│ │ ├── hooks/ # useAudioPlayer, useWebSocket, useMood, etc. +│ │ ├── store/ # Zustand stores (player, library, ui) +│ │ ├── services/ # API calls (imports from shared/) +│ │ └── utils/ +│ ├── tailwind.config.ts +│ └── package.json +├── mobile/ # React Native + Expo +│ ├── src/ +│ │ ├── components/ # Mobile-specific components +│ │ ├── screens/ # 12 screen components +│ │ ├── hooks/ +│ │ ├── store/ # Zustand (same pattern as web) +│ │ ├── services/ # API calls (imports from shared/) +│ │ └── navigation/ # React Navigation config +│ └── package.json +├── backend/ # Python FastAPI +│ ├── app/ +│ │ ├── main.py # FastAPI app, CORS, WebSocket setup +│ │ ├── routers/ +│ │ │ ├── songs.py +│ │ │ ├── playlists.py +│ │ │ ├── mood.py +│ │ │ ├── radio.py +│ │ │ ├── search.py +│ │ │ ├── lofi.py +│ │ │ ├── shareplay.py +│ │ │ ├── import_.py +│ │ │ ├── settings.py +│ │ │ ├── releases.py +│ │ │ └── events.py +│ │ ├── models/ # SQLAlchemy models +│ │ ├── schemas/ # Pydantic schemas +│ │ ├── services/ +│ │ │ ├── audio.py # Transcoding, streaming, range requests +│ │ │ ├── scanner.py # Directory scanning for music files +│ │ │ ├── mood_engine.py # Lyrics → mood classification +│ │ │ ├── lyrics.py # Genius API client +│ │ │ ├── radio_browser.py # RadioBrowser API client +│ │ │ ├── musicbrainz.py # MusicBrainz API (new releases) +│ │ │ ├── shareplay.py # WebSocket room management +│ │ │ └── events.py # Concert listing service +│ │ ├── db/ # SQLite setup, migrations +│ │ └── ws/ # WebSocket endpoint handlers +│ ├── music/ # Music file storage (scanned) +│ ├── uploads/ # Web upload destination +│ ├── static/ # Album art, mood images, etc. +│ ├── requirements.txt +│ └── Dockerfile +├── docker-compose.yml # Dev environment (backend + web) +├── .env.example +└── PLAN.md +``` + +## 3. Page Inventory (12 Pages) + +### Page 1: Home +- **Navigation Hub** (top): Profile icon + 4 feature tabs (Music, New Music, Mood, LoFi Channel) +- **Suggestions Section**: Quick-access cards → Music / New Music features +- **Currently Playing Radio**: Shows track currently playing from user's playlist +- **Mood Radio Access**: Click-through buttons to select current mood → Mood Radio page +- **Bottom Navigation Bar**: Home | Playlist | Search | Internet Radio | Create + +### Page 2: Library +- **Profile Access** (top) +- **Search Bar**: Filter user's playlists +- **Vinyl Stacks**: Visual stacks (4 vinyls per stack), each = one playlist. Playlist name below right of stack. +- **Bottom Navigation Bar** + +### Page 3: Create/Add +- **Navigation Hub** (top) +- **Tab Layout** (4 tabs): + - **Playlist**: Create playlist, add songs from library + - **Mood Playlist**: Select mood → generate playlist from mood radio engine + - **Radio**: Play randomized songs with DJ-style shuffle + - **Collab**: Browse and play shared playlists (simple link sharing) +- **Bottom Navigation Bar** + +### Page 4: Internet Radio +- **Profile Access** (top) +- **Search Bar**: Placeholder "What music is calling to you?" + magnifying glass icon +- **Currently Airing**: Map view showing local radio stations near user. Shows user location pin + nearest station. Displays current song + artist. +- **Radio Station Section**: Scrollable grid of station images → click to play +- **Bottom Navigation Bar** + +### Page 5: Search +- **Profile Access** (top) +- **Search Bar**: "What music is calling to you?" + magnifying glass +- **Feature Grid**: Colored rectangles → Music, New Music, Live Events, Internet Radio, Mood Radio +- **Music Suggestions**: 2 rows × 5 squares of album art (personalized recommendations) +- **Your Library**: Vinyl sleeve design (record emerging left). Playlist names below. +- **Now Playing Mini-Bar** (above nav): Vinyl icon + song name + artist + play/pause + skip buttons +- **Bottom Navigation Bar** + +### Page 6: Account +- **User Image** + "Welcome [username]" (top) +- **Menu Items**: + - **Plugins**: Placeholder link (to be developed later) + - **Servers**: Configure music folder paths, scan settings, remote servers + - **About You**: Listening stats, favorite artists, top genres, listening history + - **Internet Radio**: Link to Internet Radio page + - **Updates**: App changelog, version info + - **Settings & Privacy**: App preferences, audio quality, theme settings + +### Page 7: Currently Playing (Now Playing) +- **Top**: Playlist name +- **Album Art** (center, large) +- **Song Name** + **Artist Name** +- **Progress Bar**: Elapsed time display. Draggable on bar AND on overlay. +- **Overlay Seek**: 25% opacity background overlay follows progress position. Touch/drag anywhere on page to seek. +- **Controls** (L→R): Shuffle ↻ | Backward ⏮ | Play/Pause ▶/⏸ | Forward ⏭ | Plus + +- **Below Controls**: SharePlay icon + device name +- **Behaviors**: Play↔Pause toggle. Shuffle randomizes order. Back/Forward skip songs. Plus toggles song in/out of playlist. SharePlay opens device selector. + +### Page 8: SharePlay +- **Navigation Hub** (top) +- **Bottom Sheet** (draggable notch at top to expand/collapse): + - Top left: SharePlay icon + - Top right: Person icon + connected user count + - "Currently Playing" + host's name + - Vinyl image + song name + artist + - Progress bar + - **Controls**: Skip Back (prev song) | Rewind (backtrack in song) | Play/Pause | Fast Forward (advance in song) | Skip Forward (next song) + - "Up Next" + next song preview + - "Add Song to Cue" button (+ icon) +- **WebSocket sync**: Real-time state sync across all connected devices + +### Page 9: Mood Radio +- **Navigation Hub** (top) +- **"Mood Radio"** label (top left) +- **Center**: Blurred stock image in circle, surrounded by circular progress bar +- **Below Image**: Mood playlist name (e.g., "I'm Feeling Nostalgic") +- **Background**: Dynamic color matching the mood +- **Bottom**: "Currently Playing" label → upward notch icon → "Set the Mood" button +- **10 Mood Categories**: Sad, Happy, Energetic, Focused, Chill, Romantic, Angry, Nostalgic, Melancholy, Dreamy +- **Algorithm**: Fetch lyrics → keyword scoring → mood classification → rank songs → generate playlist + +### Page 10: Playlist +- **Left Sidebar** (vertical bar): + - Back icon (top) + - 5 square album cover thumbnails (user's playlists). Active playlist has play button overlay. + - Vertical progress bar (elapsed time) + - Star icon (top of bar) + - Play/Pause button (bottom of bar) +- **Main Content**: + - Playlist name + SharePlay icon (top) + - Album art with vinyl record in corner + - Song list: Record icon + song name + duration +- **Bottom**: Currently Playing bar + +### Page 11: New Releases +- **Navigation Hub** (top) +- **"New Releases"** heading +- **Repeatable Cards**: Artist image (left) + artist name + "Add Song to Playlist" (+ button) + 6 album thumbnails (right). Click album → detail view with song titles + lengths. +- **Data Source**: MusicBrainz API checks if artists in user's library have new releases +- **Bottom Navigation Bar** + +### Page 12: LoFi Channel +- **Top**: User profile (left) + "LoFi Channel" (center) +- **Channel Cards**: "LoFi" label + playlist name + atmospheric image. Click → stream in-app. +- **Streams**: Sourced from public LoFi streams (LoFi Girl, Chillhop, etc.) — proxied through backend +- **Bottom Navigation Bar** + +### Shared Components (across all pages) +- **Navigation Hub**: Profile + feature tabs +- **Bottom Navigation Bar**: Home | Playlist | Search | Internet Radio | Create +- **Now Playing Mini-Bar**: Compact player (vinyl + song + artist + controls) +- **Vinyl Component**: Reusable vinyl record / stack / sleeve visuals +- **Search Bar Component**: Reusable with placeholder support + +## 4. Backend API Endpoints + +``` +# Songs +GET /api/songs # List all songs (paginated) +GET /api/songs/{id} # Get song details +POST /api/songs/upload # Upload music file +POST /api/songs/scan # Scan configured directories +DELETE /api/songs/{id} # Remove song +GET /api/songs/{id}/stream # Stream audio (HTTP 206 range) +GET /api/songs/{id}/lyrics # Get cached lyrics + +# Playlists +GET /api/playlists # List all playlists +POST /api/playlists # Create playlist +GET /api/playlists/{id} # Get playlist + songs +PUT /api/playlists/{id} # Update playlist +DELETE /api/playlists/{id} # Delete playlist +POST /api/playlists/{id}/songs # Add song +DELETE /api/playlists/{id}/songs/{song_id} # Remove song +POST /api/playlists/{id}/share # Generate share link +GET /api/playlists/shared/{token} # Access shared playlist + +# Search +GET /api/search?q=... # Search songs/playlists + +# Mood Radio +GET /api/mood/categories # List 10 mood categories +POST /api/mood/analyze # Analyze lyrics for mood (per song or library) +GET /api/mood/{mood}/playlist # Get generated mood playlist +POST /api/mood/save # Save mood playlist as regular playlist +POST /api/mood/set # Switch current mood + +# Internet Radio +GET /api/radio/stations # List stations (RadioBrowser) +GET /api/radio/nearby # Stations near user location (GEO) +GET /api/radio/stations/{id}# Station details +GET /api/radio/stream/{id} # Proxy radio stream +GET /api/radio/current # Currently playing on active station + +# LoFi +GET /api/lofi/channels # List lo-fi channels +GET /api/lofi/stream/{id} # Proxy lo-fi stream +POST /api/lofi/add # Add new lo-fi channel + +# SharePlay +WS /ws/shareplay/{room_id} # WebSocket for sync playback +POST /api/shareplay/create # Create share room +POST /api/shareplay/join # Join room (returns room_id) +POST /api/shareplay/leave # Leave room +POST /api/shareplay/cue # Add song to cue queue +GET /api/shareplay/cue # Get cue queue +POST /api/shareplay/control # Send playback command (play/pause/skip) + +# New Releases +GET /api/releases # Check for new releases from library artists +GET /api/releases/{artist} # Get new releases for specific artist +POST /api/releases/add # Add new release songs to playlist + +# Live Events (simulated for v1) +GET /api/events # List concerts near user +POST /api/events # Add event listing + +# Settings +GET /api/settings # Get preferences +PUT /api/settings # Update preferences +GET /api/settings/servers # List configured music directories +POST /api/settings/servers # Add server/directory +DELETE /api/settings/servers/{id} # Remove server + +# Account +GET /api/account/stats # Listening stats (top artists, genres, etc.) +GET /api/account/history # Listening history +``` + +## 5. Database Schema (SQLite) + +```sql +songs ( + id, title, artist, album, duration_sec, genre, + file_path, transcoded_path, album_art_path, + added_at, file_format, file_size_bytes +) + +playlists ( + id, name, description, cover_art_path, + created_at, updated_at, mood_category, + is_shared, share_token +) + +playlist_songs (playlist_id, song_id, position, added_at) + +mood_categories ( + id, name, color_hex, description, + background_image, icon_path +) + +mood_songs (mood_id, song_id, confidence_score, analyzed_at) + +lyrics_cache ( + song_id, lyrics_text, mood_tags_json, + analyzed_at, source_url +) + +lofi_channels ( + id, name, stream_url, image_path, + description, source_platform, is_active +) + +radio_stations ( + id, name, frequency, stream_url, + location_lat, location_lon, genre, + country, language, bitrate +) + +shareplay_rooms ( + id, creator_user, created_at, + current_song_id, position_sec, + is_playing, shuffle_mode, active_connections +) + +shareplay_cue (room_id, song_id, position, added_by, added_at) + +user_settings ( + key, value, updated_at + -- Keys: audio_quality, theme, scan_directories_json, + -- user_name, user_avatar, radio_browser_instance +) + +new_releases_check ( + artist_name, last_checked_at, + new_albums_json, checked_count +) + +concert_events ( + id, name, venue, location_lat, location_lon, + date, description, image_url +) +``` + +## 6. Key Technical Implementation Details + +### 6.1 Audio Pipeline +- **Import**: Accept MP3, AAC, FLAC, WAV, OGG files via upload or directory scan +- **Transcoding**: All formats transcoded to OGG Vorbis (backend) for uniform streaming. Uses `ffmpeg` / `pydub`. +- **Metadata Extraction**: `mutagen` library extracts ID3 tags, album art, duration, genre +- **Streaming**: HTTP 206 range requests for seeking. Backend serves transcoded files. +- **Web Player**: `