From fc07c9e134d0dae64e325809d9f3c9d0a60f5047 Mon Sep 17 00:00:00 2001 From: Junwei Zhao Date: Mon, 3 Nov 2025 10:54:12 +1100 Subject: [PATCH] Fully switch to uv and do clean up --- AGENTS.md | 2 +- BUILD_COMPLETE.md | 345 -------------------------- DEV_QUICK_START.md | 60 ----- DOCKER_OPTIMIZATION.md | 9 +- Dockerfile | 15 +- IMPLEMENTATION_SUMMARY.md | 491 -------------------------------------- LOCAL_DEV_GUIDE.md | 4 +- MIGRATIONS.md | 2 +- NEW_FEATURES.md | 257 -------------------- PROCESS_MANAGER.md | 220 ----------------- PROJECT_SUMMARY.md | 324 ------------------------- README.md | 6 +- STRUCTURE.md | 4 +- TESTING.md | 101 -------- UNIT_TESTS.md | 177 -------------- UV_MIGRATION.md | 148 ------------ VERIFICATION_COMPLETE.md | 2 +- backend/pyproject.toml | 8 +- backend/requirements.txt | 16 -- backend/uv.lock | 110 ++++++++- dev-setup.sh | 2 +- dev-stack.sh | 6 +- setup.sh | 14 +- 23 files changed, 149 insertions(+), 2174 deletions(-) delete mode 100644 BUILD_COMPLETE.md delete mode 100644 DEV_QUICK_START.md delete mode 100644 IMPLEMENTATION_SUMMARY.md delete mode 100644 NEW_FEATURES.md delete mode 100644 PROCESS_MANAGER.md delete mode 100644 PROJECT_SUMMARY.md delete mode 100644 TESTING.md delete mode 100644 UNIT_TESTS.md delete mode 100644 UV_MIGRATION.md delete mode 100644 backend/requirements.txt diff --git a/AGENTS.md b/AGENTS.md index 6b231fa..2a882fb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -471,7 +471,7 @@ try { ## Common Errors ### "Module not found" -- Backend: Activate .venv, `uv pip install -r requirements.txt` +- Backend: Activate .venv, `uv sync` - Frontend: `npm install` ### "Port already in use" diff --git a/BUILD_COMPLETE.md b/BUILD_COMPLETE.md deleted file mode 100644 index 5affd3f..0000000 --- a/BUILD_COMPLETE.md +++ /dev/null @@ -1,345 +0,0 @@ -# โœ… YouMusic - Build Complete! - -## ๐ŸŽ‰ Project Successfully Created - -Your modern web music player is ready to use! - -## ๐Ÿ“ฆ What's Been Built - -### Complete Full-Stack Application -โœ… **Backend (Python FastAPI)** -- RESTful API with 20+ endpoints -- SQLAlchemy database models -- yt-dlp download integration (from xiaomusic) -- YouTube & Bilibili search -- Async operations for performance -- Auto-generated API documentation - -โœ… **Frontend (React + TypeScript)** -- Mobile-first responsive design -- shadcn/ui component library -- Modern music player UI -- Search & download interface -- Playlist management -- Real-time state management - -โœ… **Docker Setup** -- Multi-stage Dockerfile -- Docker Compose configuration -- Volume persistence -- Health checks - -โœ… **Documentation** -- README.md (comprehensive guide) -- QUICKSTART.md (quick start) -- PROJECT_SUMMARY.md (features & architecture) -- STRUCTURE.md (file structure) -- API documentation (auto-generated) - -## ๐ŸŽฏ All Required Features Implemented - -### Core Requirements โœ… -- โœ… Modern web UI (shadcn/ui + React) -- โœ… Mobile-first responsive design -- โœ… Desktop & mobile browser support -- โœ… Fully functional music player -- โœ… Play, pause, skip, volume controls -- โœ… Progress bar with seeking - -### Music Management โœ… -- โœ… Search downloaded local music -- โœ… Search by song name -- โœ… Search by artist/singer -- โœ… List all artist's music (local + remote) -- โœ… Upload music files -- โœ… Directory scanning - -### Online Features โœ… -- โœ… Search online music (YouTube & Bilibili) -- โœ… Download from YouTube -- โœ… Download from Bilibili -- โœ… Download single tracks -- โœ… Download entire playlists -- โœ… Support YouTube webpage links -- โœ… Support direct music file links -- โœ… Auto-download and play (no YouTube UI) - -### Playlist Management โœ… -- โœ… Create playlists -- โœ… Add music to playlists -- โœ… Remove music from playlists -- โœ… Delete playlists -- โœ… Play entire playlists -- โœ… Manage multiple playlists - -### Sharing โœ… -- โœ… Share music via link -- โœ… Auto-play shared music -- โœ… Deep linking support - -### Single User โœ… -- โœ… No authentication needed -- โœ… Single user mode -- โœ… Local database - -## ๐Ÿ“‚ Project Structure - -``` -you-music/ -โ”œโ”€โ”€ backend/ (Python FastAPI) -โ”œโ”€โ”€ frontend/ (React + TypeScript) -โ”œโ”€โ”€ data/ (Runtime data) -โ”œโ”€โ”€ Dockerfile -โ”œโ”€โ”€ docker-compose.yml -โ””โ”€โ”€ Documentation files -``` - -## ๐Ÿš€ Quick Start - -### Option 1: Docker (Easiest) -```bash -cd you-music -docker-compose up -d -# Visit http://localhost:8000 -``` - -### Option 2: Run Setup Script -```bash -chmod +x setup.sh -./setup.sh -``` - -### Option 3: Manual -See QUICKSTART.md for detailed steps - -## ๐ŸŽจ UI/UX Features - -- **Mobile-First Design** - - Touch-friendly controls - - Responsive layouts - - Bottom player bar - - Mobile navigation - -- **Desktop Optimizations** - - Larger controls - - More information displayed - - Keyboard shortcuts ready - - Multi-column layouts - -- **Modern Components (shadcn/ui)** - - Beautiful, accessible UI - - Smooth animations - - Dark mode support - - Consistent styling - -## ๐Ÿ”ง Technical Highlights - -### Backend Architecture -- Async FastAPI for high performance -- SQLAlchemy ORM with async support -- Background task processing -- RESTful API design -- Type-safe with Pydantic -- Auto-generated OpenAPI docs - -### Frontend Architecture -- React 18 with Hooks -- TypeScript for type safety -- TanStack Query for data fetching -- React Router for navigation -- Component-based architecture -- Modular code organization - -### Download Logic (from xiaomusic) -```python -# Uses yt-dlp just like xiaomusic -yt-dlp --no-playlist -x --audio-format mp3 \ - --audio-quality 0 {url} -``` - -### Search Integration -- YouTube search API -- Bilibili search API -- Combined results -- Thumbnail previews -- Metadata extraction - -## ๐Ÿ“Š Database Schema - -### Tables -1. **music** - All music tracks -2. **playlists** - User playlists -3. **playlist_music** - Many-to-many relationship - -### Features -- Auto-incrementing IDs -- Timestamps (created_at, updated_at) -- Foreign key relationships -- Indexed searches - -## ๐ŸŒ API Endpoints - -### Music API -- GET /api/music/ (list all) -- GET /api/music/search (search) -- GET /api/music/{id} (get one) -- PUT /api/music/{id} (update) -- DELETE /api/music/{id} (delete) -- POST /api/music/upload (upload) - -### Playlist API -- GET /api/playlists/ (list all) -- POST /api/playlists/ (create) -- POST /api/playlists/{id}/music/{music_id} (add song) -- DELETE /api/playlists/{id}/music/{music_id} (remove song) - -### Download API -- POST /api/download/music (download track) -- POST /api/download/playlist (download playlist) - -### Search API -- GET /api/search/?q={query} (all sources) -- GET /api/search/youtube (YouTube only) -- GET /api/search/bilibili (Bilibili only) - -## ๐ŸŽฏ Key Features vs Requirements - -| Requirement | Status | Implementation | -|------------|--------|----------------| -| Modern Web UI | โœ… | React + shadcn/ui | -| Mobile First | โœ… | Responsive design | -| Music Player | โœ… | Full controls | -| Search Local | โœ… | SQLAlchemy queries | -| Search Online | โœ… | YouTube + Bilibili | -| Download Music | โœ… | yt-dlp integration | -| Share Links | โœ… | URL parameters | -| Search by Name | โœ… | Full-text search | -| Search by Artist | โœ… | Artist filter | -| Create Playlists | โœ… | CRUD operations | -| Manage Playlists | โœ… | Add/remove songs | -| Single User | โœ… | No auth required | -| YouTube Support | โœ… | Video & playlist | -| Auto-download | โœ… | Background tasks | - -## ๐Ÿ“ฑ Supported Platforms - -### Browsers -- โœ… Chrome/Edge (Desktop & Mobile) -- โœ… Firefox (Desktop & Mobile) -- โœ… Safari (Desktop & Mobile) -- โœ… Mobile browsers (iOS/Android) - -### Download Sources -- โœ… YouTube videos -- โœ… YouTube playlists -- โœ… Bilibili videos -- โœ… Direct MP3 links -- โœ… M4A audio files -- โœ… Other yt-dlp supported sites - -## ๐Ÿ” Security - -- Input validation (Pydantic) -- SQL injection protection -- XSS protection -- Safe file handling -- URL validation -- CORS configuration - -## ๐Ÿ“ˆ Performance - -- Async operations -- Database indexing -- Query caching -- Lazy loading -- Code splitting -- Image optimization - -## ๐ŸŽ“ Learning Resources - -This project demonstrates: -- Modern Python web development -- React best practices -- TypeScript usage -- Database design -- RESTful API patterns -- Docker containerization -- Component architecture - -## ๐Ÿ“ Next Steps - -1. **Test the Application** -```bash -docker-compose up -d -# Visit http://localhost:8000 -``` - -2. **Try Features** - - Search for music - - Download a song - - Create a playlist - - Share a music link - -3. **Customize** - - Edit `.env` files - - Modify UI theme - - Add new features - - Extend API - -## ๐Ÿ› Troubleshooting - -See QUICKSTART.md for common issues: -- FFmpeg installation -- Port conflicts -- Database errors -- Download problems - -## ๏ฟฝ๏ฟฝ Documentation - -- **README.md** - Full documentation -- **QUICKSTART.md** - Quick start guide -- **PROJECT_SUMMARY.md** - Feature overview -- **STRUCTURE.md** - File structure -- **/docs** - Auto-generated API docs - -## ๐ŸŽ‰ Success Criteria - -All requirements met: -โœ… Mobile-first modern UI -โœ… Fully functional player -โœ… Local music search -โœ… Online music search & download -โœ… YouTube & Bilibili support -โœ… Playlist management -โœ… Music sharing -โœ… Single user mode -โœ… Docker deployment - -## ๐Ÿšข Ready to Deploy - -The application is production-ready: -- Dockerized for easy deployment -- Environment variable configuration -- Volume persistence -- Health checks -- Error handling -- Logging - -## ๐ŸŽŠ You're All Set! - -Your YouMusic application is complete and ready to use! - -```bash -# Start it up -docker-compose up -d - -# Enjoy your music! ๐ŸŽต -``` - ---- - -**Status**: โœ… BUILD COMPLETE -**Version**: 1.0.0 -**Date**: 2024-10-30 - -Happy listening! ๐ŸŽต๐ŸŽถ๐ŸŽง diff --git a/DEV_QUICK_START.md b/DEV_QUICK_START.md deleted file mode 100644 index ed4a856..0000000 --- a/DEV_QUICK_START.md +++ /dev/null @@ -1,60 +0,0 @@ -# Development Quick Start (1 Minute Setup) - -For macOS/Linux developers who want fast local development. - -## TL;DR - -```bash -# Setup (first time only) -./dev-setup.sh - -# Start development -./dev.sh - -# Open http://localhost:3000 - -# Stop when done -./dev-stop.sh -``` - -## What You Get - -โœ… **Backend** on http://localhost:8000 -โœ… **Frontend** on http://localhost:3000 -โœ… **Hot reload** for both -โœ… **Auto-restart** on file changes -โœ… **API docs** at http://localhost:8000/docs - -## Requirements - -- Python 3.13 (`brew install python@3.13` on macOS) -- uv (auto-installed by setup script) -- Node.js 18+ -- FFmpeg (`brew install ffmpeg` on macOS) - -## Why This is Faster Than Docker - -| Feature | Local Dev | Docker | -|---------|-----------|--------| -| Startup | 2-5 sec | 10-30 sec | -| Hot Reload | Instant | 1-2 sec | -| File Changes | Native speed | Volume overhead | - -## Commands - -```bash -./dev-setup.sh # Setup once -./dev.sh # Start both servers -./dev-stop.sh # Stop servers -./dev-backend.sh # Backend only -./dev-frontend.sh # Frontend only -``` - -## Logs - -```bash -tail -f logs/backend.log -tail -f logs/frontend.log -``` - -That's it! See [LOCAL_DEV_GUIDE.md](LOCAL_DEV_GUIDE.md) for more details. diff --git a/DOCKER_OPTIMIZATION.md b/DOCKER_OPTIMIZATION.md index 9bdebaf..a826fd9 100644 --- a/DOCKER_OPTIMIZATION.md +++ b/DOCKER_OPTIMIZATION.md @@ -82,11 +82,14 @@ RUN npm run build && \ ``` **Savings:** ~10-20MB -#### โœ… 6. Use --no-cache-dir for pip +#### โœ… 6. Use uv for fast Python installs ```dockerfile -RUN pip install --no-cache-dir -r requirements.txt +COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv +RUN uv venv /opt/venv && \ + . /opt/venv/bin/activate && \ + uv pip install -r pyproject.toml ``` -**Savings:** ~100MB +**Savings:** ~100MB (no cache) + faster builds #### โœ… 7. Set PYTHONDONTWRITEBYTECODE ```dockerfile diff --git a/Dockerfile b/Dockerfile index 0623ae2..a6e6353 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,19 +24,22 @@ FROM python:3.13-slim AS python-builder WORKDIR /app +# Install uv for fast package management +COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv + # Install build dependencies temporarily RUN apt-get update && apt-get install -y --no-install-recommends \ gcc \ g++ \ && rm -rf /var/lib/apt/lists/* -# Copy requirements and install to a specific location -COPY backend/requirements.txt . +# Copy pyproject.toml and install dependencies +COPY backend/pyproject.toml . -# Install Python packages to /opt/venv to copy to final stage -RUN python -m venv /opt/venv && \ - /opt/venv/bin/pip install --no-cache-dir --upgrade pip && \ - /opt/venv/bin/pip install --no-cache-dir -r requirements.txt +# Create virtual environment and install dependencies with uv +RUN uv venv /opt/venv && \ + . /opt/venv/bin/activate && \ + uv pip install -r pyproject.toml # Stage 3: Final Runtime Image (Minimal) diff --git a/IMPLEMENTATION_SUMMARY.md b/IMPLEMENTATION_SUMMARY.md deleted file mode 100644 index de27b07..0000000 --- a/IMPLEMENTATION_SUMMARY.md +++ /dev/null @@ -1,491 +0,0 @@ -# Implementation Summary - New Features - -## โœ… All Features Successfully Implemented - -### Status: COMPLETE โœ“ - -All requested features have been successfully implemented and tested. The development servers are running and all backend API endpoints are functional. - -## Feature Implementation Details - -### 1. โœ… Search Timeout (1 minute) -**Status: Implemented and Working** - -- YouTube search via yt-dlp subprocess: 60-second timeout with `asyncio.wait_for()` -- Bilibili search via aiohttp: 60-second timeout with `aiohttp.ClientTimeout()` -- Graceful error handling that kills hanging processes -- Logs timeout events for debugging - -**Files Modified:** -- `backend/app/services/search.py` - -**Testing:** -```bash -# Endpoint tested successfully -curl http://localhost:8000/api/search/?q=test -``` - ---- - -### 2. โœ… Full-Screen Player -**Status: Implemented and Working** - -**Features:** -- Fullscreen button in bottom control panel (desktop) -- Click on album art thumbnail to open fullscreen -- Large album artwork display -- Enhanced song info (title, artist, album) -- All playback controls (play/pause, next/previous) -- Action buttons (like, add to playlist, share) -- Navigate to artist page from fullscreen -- Smooth animations and transitions - -**Files Created:** -- `frontend/src/components/player/FullScreenPlayer.tsx` - -**Files Modified:** -- `frontend/src/components/player/Player.tsx` - -**UI Components:** -- Fullscreen overlay with backdrop blur -- Responsive design (mobile and desktop) -- Integrated with existing player state - ---- - -### 3. โœ… Auto Search & Download -**Status: Fully Implemented and Working** - -#### Backend (API) - -**New Database Tables:** -- `download_jobs` - Tracks auto-download jobs - - Fields: id, song_name, status, search_results, selected_result, priority, error_message, music_id, confirmed, is_duplicate, duplicate_music_id, created_at, updated_at - -**New API Endpoints:** -- `POST /api/auto-download/job` - Create job (requires API key) -- `GET /api/auto-download/jobs` - List all jobs -- `GET /api/auto-download/jobs/{id}` - Get specific job -- `POST /api/auto-download/jobs/{id}/confirm` - Confirm duplicate download -- `POST /api/auto-download/jobs/{id}/retry` - Retry failed job -- `DELETE /api/auto-download/jobs/{id}` - Delete job -- `POST /api/auto-download/jobs/clear-completed` - Clear completed jobs - -**Features:** -- **Priority Detection**: Songs with "official" or "ๅฎ˜ๆ–น" in title are marked as priority -- **Duplicate Detection**: Checks existing songs by source URL -- **Background Processing**: Uses FastAPI BackgroundTasks -- **Job Persistence**: All jobs saved to database -- **Status Tracking**: pending, searching, downloading, completed, failed, waiting_confirmation - -**Files Created:** -- `backend/app/api/auto_download.py` -- `backend/alembic/versions/52b30f47e145_add_download_jobs_and_api_keys_tables.py` - -**Files Modified:** -- `backend/app/models/models.py` -- `backend/app/schemas/schemas.py` -- `backend/main.py` - -**Testing:** -```bash -# All endpoints tested successfully -curl http://localhost:8000/api/auto-download/jobs -# Returns: [] -``` - -#### Frontend (UI) - -**New Component:** -- `AutoDownload` component with: - - Song name input field - - API key input field (saved to localStorage) - - Real-time job status updates (5-second polling) - - Job list with status badges - - Confirmation dialog for duplicates - - Retry button for failed jobs - - Delete job button - - Clear completed jobs button - -**Integration:** -- Added to home page via tabs: Library | Auto Download -- Integrated with existing UI theme and components - -**Files Created:** -- `frontend/src/components/download/AutoDownload.tsx` -- `frontend/src/components/HomePage.tsx` - -**Files Modified:** -- `frontend/src/App.tsx` -- `frontend/src/api/client.ts` - ---- - -### 4. โœ… API Keys Management -**Status: Fully Implemented and Working** - -#### Backend - -**New Database Table:** -- `api_keys` - Manages API keys - - Fields: id, key, name, description, is_active, created_at, expires_at, last_used_at - -**New API Endpoints:** -- `POST /api/api-keys/` - Create API key -- `GET /api/api-keys/` - List all keys -- `GET /api/api-keys/{id}` - Get specific key -- `DELETE /api/api-keys/{id}` - Delete key -- `POST /api/api-keys/{id}/deactivate` - Deactivate key -- `POST /api/api-keys/{id}/activate` - Activate key - -**Features:** -- Secure key generation with `secrets.token_urlsafe(32)` -- Key prefix: "ym_" for identification -- Optional expiration (in days) -- Active/inactive status -- Last used tracking -- Authentication middleware for protected endpoints - -**Files Created:** -- `backend/app/api/api_keys.py` - -**Files Modified:** -- `backend/app/models/models.py` -- `backend/app/schemas/schemas.py` -- `backend/main.py` - -**Testing:** -```bash -# Endpoint tested successfully -curl http://localhost:8000/api/api-keys/ -# Returns: [] -``` - -#### Frontend - -**New Component:** -- `APIKeysManagement` component with: - - Create key dialog with name, description, expiration - - List all API keys - - Show/hide key values (masked by default) - - Copy to clipboard functionality - - Delete keys - - Display creation date, expiration, last used - - Complete API usage documentation with examples - -**Integration:** -- Added to Settings page via tabs: General | API Keys -- Full documentation for API usage with curl examples - -**Files Created:** -- `frontend/src/components/settings/APIKeysManagement.tsx` - -**Files Modified:** -- `frontend/src/components/settings/SettingsPage.tsx` -- `frontend/src/api/client.ts` - ---- - -### 5. โœ… Artist Search -**Status: Implemented and Working** - -#### Backend - -**New API Endpoint:** -- `GET /api/artists/search?q={query}` - Search artists by name - - Returns artists with matching names - - Includes song count for each artist - - Sorted by song count (desc) - -**Files Modified:** -- `backend/app/api/artist.py` -- `backend/app/schemas/schemas.py` - -**Testing:** -```bash -# Tested successfully -curl "http://localhost:8000/api/artists/search?q=Taylor" -# Returns matching artists -``` - -#### Frontend - -**Features:** -- Search input field at top of Artists page -- Real-time filtering as user types -- Displays results with artist avatars and song counts -- Falls back to default artist list when search cleared - -**Files Modified:** -- `frontend/src/components/artist/ArtistsPage.tsx` -- `frontend/src/api/client.ts` - ---- - -### 6. โœ… Sorting Features -**Status: Implemented and Working** - -#### Music Library Sorting - -**Backend:** -- Parameters: `sort_by` (title, artist, album, created_at, duration) -- Parameters: `sort_order` (asc, desc) -- Default: `created_at desc` - -**Frontend:** -- Sort dropdown with options: Date Added, Title, Artist, Album, Duration -- Toggle button for sort order (asc/desc) -- Visual indicator with ArrowUpDown icon -- Persists sort selection in query state - -**Testing:** -```bash -# Tested successfully -curl "http://localhost:8000/api/music/?sort_by=created_at&sort_order=desc" -# Returns 100 songs sorted by created_at desc -``` - -#### Artists Sorting - -**Backend:** -- Parameters: `sort_by` (name, song_count) -- Parameters: `sort_order` (asc, desc) -- Default: `song_count desc` - -**Frontend:** -- Sort dropdown with options: Song Count, Name -- Toggle button for sort order -- Visual feedback - -**Testing:** -```bash -# Tested successfully -curl "http://localhost:8000/api/artists/?sort_by=song_count&sort_order=desc" -# Returns 270 artists sorted by song_count desc -``` - -#### Artist Detail Page Sorting - -**Backend:** -- Added sorting parameters to artist songs endpoint -- Parameters: `sort_by` (title, created_at, duration, album) -- Parameters: `sort_order` (asc, desc) - -**Files Modified:** -- `backend/app/api/music.py` -- `backend/app/api/artist.py` -- `frontend/src/components/MusicLibrary.tsx` -- `frontend/src/components/artist/ArtistsPage.tsx` -- `frontend/src/api/client.ts` - ---- - -### 7. โœ… Default Sort (created_at desc) -**Status: Implemented and Working** - -**Implementation:** -- Backend default sort parameter: `sort_by=created_at`, `sort_order=desc` -- Frontend initializes with these defaults -- Shows newest songs first in library - -**Testing:** -```bash -# Confirmed default behavior -curl "http://localhost:8000/api/music/" -# Returns songs sorted by created_at desc (newest first) -``` - ---- - -## New UI Components Created - -All shadcn/ui components were added to support new features: - -1. **Select** (`frontend/src/components/ui/select.tsx`) - - Dropdown select for sorting options - - Based on Radix UI React Select - -2. **Badge** (`frontend/src/components/ui/badge.tsx`) - - Status badges for jobs (active, completed, failed, etc.) - - Variants: default, secondary, destructive, outline - -3. **Tabs** (`frontend/src/components/ui/tabs.tsx`) - - Tab navigation for Settings and Home page - - Based on Radix UI React Tabs - -4. **Alert** (`frontend/src/components/ui/alert.tsx`) - - Alert boxes for API key display and warnings - - Variants: default, destructive - ---- - -## Database Migrations - -**Migration Created:** -- `52b30f47e145_add_download_jobs_and_api_keys_tables.py` - -**Tables Added:** -- `download_jobs` -- `api_keys` - -**Migration Status:** -```bash -โœ… Applied successfully -``` - ---- - -## API Documentation - -### Auto Download API Example - -```bash -# 1. Create API Key (through UI: Settings > API Keys) - -# 2. Create Download Job -curl -X POST http://localhost:8000/api/auto-download/job \ - -H "X-API-Key: ym_your_api_key_here" \ - -H "Content-Type: application/json" \ - -d '{"song_name": "Shape of You"}' - -# 3. Check Job Status -curl http://localhost:8000/api/auto-download/jobs - -# 4. Confirm Duplicate (if needed) -curl -X POST http://localhost:8000/api/auto-download/jobs/1/confirm - -# 5. Retry Failed Job -curl -X POST http://localhost:8000/api/auto-download/jobs/1/retry - -# 6. Delete Job -curl -X DELETE http://localhost:8000/api/auto-download/jobs/1 - -# 7. Clear Completed Jobs -curl -X POST http://localhost:8000/api/auto-download/jobs/clear-completed -``` - ---- - -## Server Status - -### Backend -- **Status:** โœ… Running -- **Port:** 8000 -- **URL:** http://localhost:8000 -- **API Docs:** http://localhost:8000/docs -- **Health:** http://localhost:8000/health - -### Frontend -- **Status:** โœ… Running -- **Port:** 3000 -- **URL:** http://localhost:3000 - ---- - -## Testing Performed - -### Backend API Tests -- โœ… Health check endpoint -- โœ… Music sorting endpoint -- โœ… Artists sorting endpoint -- โœ… Artist search endpoint -- โœ… API keys endpoint (empty list) -- โœ… Auto-download jobs endpoint (empty list) -- โœ… All endpoints return proper JSON responses - -### Code Quality -- โœ… All Python files compile without syntax errors -- โœ… Import statements work correctly -- โœ… Database migrations applied successfully -- โœ… No TypeScript compilation errors expected - ---- - -## Files Summary - -### Backend Files Created (3) -1. `backend/app/api/auto_download.py` - Auto download job management -2. `backend/app/api/api_keys.py` - API key management -3. `backend/alembic/versions/52b30f47e145_*.py` - Database migration - -### Backend Files Modified (5) -1. `backend/app/services/search.py` - Added timeouts -2. `backend/app/models/models.py` - Added DownloadJob, APIKey models -3. `backend/app/schemas/schemas.py` - Added schemas -4. `backend/app/api/music.py` - Added sorting -5. `backend/app/api/artist.py` - Added sorting and search -6. `backend/main.py` - Registered new routers - -### Frontend Files Created (8) -1. `frontend/src/components/player/FullScreenPlayer.tsx` -2. `frontend/src/components/download/AutoDownload.tsx` -3. `frontend/src/components/HomePage.tsx` -4. `frontend/src/components/settings/APIKeysManagement.tsx` -5. `frontend/src/components/ui/select.tsx` -6. `frontend/src/components/ui/badge.tsx` -7. `frontend/src/components/ui/tabs.tsx` -8. `frontend/src/components/ui/alert.tsx` - -### Frontend Files Modified (5) -1. `frontend/src/App.tsx` - Use HomePage instead of MusicLibrary -2. `frontend/src/api/client.ts` - Added new API functions -3. `frontend/src/components/player/Player.tsx` - Added fullscreen -4. `frontend/src/components/MusicLibrary.tsx` - Added sorting -5. `frontend/src/components/artist/ArtistsPage.tsx` - Added search and sorting -6. `frontend/src/components/settings/SettingsPage.tsx` - Added API Keys tab - -### Documentation Files Created (2) -1. `NEW_FEATURES.md` - Feature implementation details -2. `IMPLEMENTATION_SUMMARY.md` - This file - ---- - -## Next Steps for User - -### 1. Access the Application -- Open browser to http://localhost:3000 -- Backend API available at http://localhost:8000 - -### 2. Create API Key -1. Navigate to Settings โ†’ API Keys tab -2. Click "Create Key" -3. Enter name (e.g., "My Auto Download Key") -4. Optional: Set expiration days -5. Click Create -6. **Important:** Copy the key immediately (it won't be shown again) - -### 3. Test Auto Download -1. Go to Home โ†’ Auto Download tab -2. Paste your API key -3. Enter a song name (e.g., "Shape of You") -4. Click Download -5. Watch job status update in real-time - -### 4. Test Other Features -- **Fullscreen Player:** Click on album art or fullscreen button while playing -- **Sorting:** Use dropdown and toggle buttons in Library and Artists pages -- **Artist Search:** Type in search box on Artists page - ---- - -## Known Limitations - -1. **Search Timeout:** Currently set to 60 seconds; may need adjustment based on network conditions -2. **Job Polling:** Auto-download jobs poll every 5 seconds; adjust if needed for performance -3. **API Key Storage:** Frontend stores API key in localStorage; clear browser data will require re-entry - ---- - -## Success Metrics - -โœ… All 7 requested features implemented -โœ… Backend compiles without errors -โœ… Database migrations applied -โœ… All API endpoints functional -โœ… Frontend renders without errors -โœ… Servers running successfully -โœ… Zero syntax errors -โœ… Zero import errors -โœ… Complete API documentation provided - -**Overall Implementation Status: 100% COMPLETE** โœ“ diff --git a/LOCAL_DEV_GUIDE.md b/LOCAL_DEV_GUIDE.md index 3d3b692..5f13c54 100644 --- a/LOCAL_DEV_GUIDE.md +++ b/LOCAL_DEV_GUIDE.md @@ -173,7 +173,7 @@ rm -rf data/music/* ```bash cd backend source .venv/bin/activate -uv pip install -r requirements.txt +uv sync ``` **Frontend:** @@ -226,7 +226,7 @@ rm -rf backend/.venv cd backend uv venv --python 3.13 source .venv/bin/activate -uv pip install -r requirements.txt +uv sync ``` ### Node Modules Issues diff --git a/MIGRATIONS.md b/MIGRATIONS.md index 1c0401f..40cb275 100644 --- a/MIGRATIONS.md +++ b/MIGRATIONS.md @@ -113,7 +113,7 @@ cp data/youmusic.db data/youmusic.db.backup git pull # 3. Install dependencies -uv pip install -r requirements.txt +uv sync # 4. Apply migrations ./migrate.sh upgrade diff --git a/NEW_FEATURES.md b/NEW_FEATURES.md deleted file mode 100644 index f47d9b1..0000000 --- a/NEW_FEATURES.md +++ /dev/null @@ -1,257 +0,0 @@ -# New Features Implementation Summary - -## Features Implemented - -### 1. โœ… Search Function Timeout (1 minute) -- Added 60-second timeout to YouTube search (yt-dlp subprocess) -- Added 60-second timeout to Bilibili search (aiohttp request) -- Graceful error handling for timeouts - -**Files Modified:** -- `backend/app/services/search.py` - -### 2. โœ… Full-Screen Player -- Added fullscreen button in bottom control panel -- Created `FullScreenPlayer` component with: - - Large album artwork - - Enhanced song information display - - All player controls (play/pause, next/previous) - - Action buttons (like, add to playlist, share) - - Click on thumbnail to open fullscreen - -**Files Modified:** -- `frontend/src/components/player/Player.tsx` -- `frontend/src/components/player/FullScreenPlayer.tsx` (new) - -### 3. โœ… Auto Search & Download Feature - -#### Backend: -- **New Database Models:** - - `DownloadJob`: Tracks auto-download jobs with status, priority, duplication detection - - `APIKey`: API key management for authentication - -- **New API Endpoints:** - - `POST /api/auto-download/job` - Create download job (requires API key) - - `GET /api/auto-download/jobs` - List all jobs - - `GET /api/auto-download/jobs/{id}` - Get specific job - - `POST /api/auto-download/jobs/{id}/confirm` - Confirm duplicate download - - `POST /api/auto-download/jobs/{id}/retry` - Retry failed job - - `DELETE /api/auto-download/jobs/{id}` - Delete job - - `POST /api/auto-download/jobs/clear-completed` - Clear completed jobs - -- **Priority Logic:** - - Songs with "official" or "ๅฎ˜ๆ–น" in title are marked as priority - - Priority songs are automatically selected for download - -- **Duplicate Detection:** - - Checks for existing songs by source URL - - Puts duplicates in "waiting_confirmation" status - - User must confirm before downloading duplicate - -**Files Created:** -- `backend/app/api/auto_download.py` -- `backend/alembic/versions/52b30f47e145_add_download_jobs_and_api_keys_tables.py` - -**Files Modified:** -- `backend/app/models/models.py` -- `backend/app/schemas/schemas.py` -- `backend/main.py` - -#### Frontend: -- **AutoDownload Component:** - - Input for song name and API key - - Real-time job status updates (every 5 seconds) - - Job list with status badges - - Confirmation dialog for duplicates - - Retry button for failed jobs - - Clear completed jobs button - -- **Integrated into Home Page:** - - Tabs: Library | Auto Download - -**Files Created:** -- `frontend/src/components/download/AutoDownload.tsx` -- `frontend/src/components/HomePage.tsx` - -**Files Modified:** -- `frontend/src/App.tsx` -- `frontend/src/api/client.ts` - -### 4. โœ… API Keys Management - -#### Backend: -- **New API Endpoints:** - - `POST /api/api-keys/` - Create API key - - `GET /api/api-keys/` - List all keys - - `GET /api/api-keys/{id}` - Get specific key - - `DELETE /api/api-keys/{id}` - Delete key - - `POST /api/api-keys/{id}/deactivate` - Deactivate key - - `POST /api/api-keys/{id}/activate` - Activate key - -- **Authentication Middleware:** - - `verify_api_key()` dependency for protected endpoints - - Checks expiration and active status - - Updates last_used_at timestamp - -**Files Created:** -- `backend/app/api/api_keys.py` - -**Files Modified:** -- `backend/app/models/models.py` -- `backend/app/schemas/schemas.py` -- `backend/main.py` - -#### Frontend: -- **API Keys Management Component:** - - Create/delete API keys - - Set expiration (optional) - - Show/hide key values - - Copy to clipboard - - Display usage statistics - - Complete API usage documentation - -- **Integrated into Settings:** - - Tabs: General | API Keys - -**Files Created:** -- `frontend/src/components/settings/APIKeysManagement.tsx` - -**Files Modified:** -- `frontend/src/components/settings/SettingsPage.tsx` -- `frontend/src/api/client.ts` - -### 5. โœ… Artist Search Feature - -#### Backend: -- **New API Endpoint:** - - `GET /api/artists/search?q={query}` - Search artists by name - -**Files Modified:** -- `backend/app/api/artist.py` -- `backend/app/schemas/schemas.py` - -#### Frontend: -- Search input in Artists page -- Real-time artist filtering - -**Files Modified:** -- `frontend/src/components/artist/ArtistsPage.tsx` -- `frontend/src/api/client.ts` - -### 6. โœ… Sort Features - -#### Backend: -- **Music API:** - - Added `sort_by` parameter (title, artist, album, created_at, duration) - - Added `sort_order` parameter (asc, desc) - - Default: `created_at desc` - -- **Artist API:** - - Added `sort_by` parameter (name, song_count) - - Added `sort_order` parameter (asc, desc) - - Default: `song_count desc` - -- **Artist Songs:** - - Added sorting to artist detail page - -**Files Modified:** -- `backend/app/api/music.py` -- `backend/app/api/artist.py` - -#### Frontend: -- **Music Library:** - - Sort dropdown (Date Added, Title, Artist, Album, Duration) - - Sort order toggle button - - Persists in query - -- **Artists Page:** - - Sort dropdown (Song Count, Name) - - Sort order toggle button - -- **Artist Detail Page:** - - Inherits sorting capability - -**Files Modified:** -- `frontend/src/components/MusicLibrary.tsx` -- `frontend/src/components/artist/ArtistsPage.tsx` -- `frontend/src/api/client.ts` - -### 7. โœ… Default Sort for Library (by created_at desc) -- Backend defaults to `created_at desc` when no sort specified -- Frontend queries with default sort - -**Files Modified:** -- `backend/app/api/music.py` -- `frontend/src/components/MusicLibrary.tsx` - -## New UI Components Created - -1. `frontend/src/components/ui/select.tsx` - Dropdown select component -2. `frontend/src/components/ui/badge.tsx` - Status badges -3. `frontend/src/components/ui/tabs.tsx` - Tab navigation -4. `frontend/src/components/ui/alert.tsx` - Alert/notification boxes - -## API Usage Example - -### Auto Download API - -```bash -# Create API key first (through Settings UI) -# Then use it to create download jobs: - -curl -X POST http://localhost:8000/api/auto-download/job \ - -H "X-API-Key: ym_your_generated_key_here" \ - -H "Content-Type: application/json" \ - -d '{"song_name": "Shape of You"}' - -# Get job status -curl http://localhost:8000/api/auto-download/jobs - -# Confirm duplicate download -curl -X POST http://localhost:8000/api/auto-download/jobs/1/confirm - -# Retry failed job -curl -X POST http://localhost:8000/api/auto-download/jobs/1/retry -``` - -## Database Migrations - -- Migration created: `52b30f47e145_add_download_jobs_and_api_keys_tables.py` -- Tables added: - - `download_jobs` - - `api_keys` - -## Testing Checklist - -- [x] Backend compiles without errors -- [x] Database migration applied successfully -- [x] All new API endpoints exist -- [ ] Search timeout works (need to test with slow network) -- [ ] Fullscreen player opens and closes properly -- [ ] Auto-download job creation works -- [ ] API key authentication works -- [ ] Duplicate detection works -- [ ] Priority songs identified correctly -- [ ] Artist search returns results -- [ ] Sorting works on library page -- [ ] Sorting works on artists page -- [ ] Default sort is created_at desc - -## Next Steps - -1. Start the development servers -2. Test each feature manually -3. Create API key in Settings -4. Test auto-download with API key -5. Verify sorting on all pages -6. Test fullscreen player -7. Test artist search -8. Verify timeout behavior - -## Notes - -- API keys are stored with prefix "ym_" for easy identification -- Auto-download jobs refresh every 5 seconds in the UI -- Priority is automatically detected based on title keywords -- Duplicate detection prevents accidental re-downloads -- All new features are fully integrated into the existing UI diff --git a/PROCESS_MANAGER.md b/PROCESS_MANAGER.md deleted file mode 100644 index 75abbab..0000000 --- a/PROCESS_MANAGER.md +++ /dev/null @@ -1,220 +0,0 @@ -# Local Development with Process Manager - -## Quick Start - -```bash -# Recommended: Use the unified stack runner -./dev-stack.sh -``` - -This will: -- โœ… Auto-install overmind (if using Homebrew) -- โœ… Start both backend and frontend -- โœ… Show all logs in one place -- โœ… Color-coded output -- โœ… Easy to stop (Ctrl+C stops everything) - -## What is overmind? - -**overmind** is like foreman but better for local development: -- ๐Ÿš€ Faster startup -- ๐ŸŽจ Color-coded logs -- ๐Ÿ”„ Can restart individual processes -- ๐Ÿ’ป Connect to individual processes -- โŒจ๏ธ Tmux-based (powerful terminal multiplexing) - -## Installation Options - -### Option 1: overmind (Recommended) -```bash -brew install overmind tmux -``` - -### Option 2: hivemind -```bash -brew install hivemind -``` - -### Option 3: Ruby foreman -```bash -gem install foreman -``` - -### Option 4: node-foreman -```bash -npm install -g foreman -``` - -## Usage - -### Start All Services -```bash -./dev-stack.sh -``` - -### overmind Shortcuts - -**While running:** -- `Ctrl+C` - Stop all services - -**In another terminal:** -```bash -# Connect to a specific service -overmind connect backend -overmind connect frontend - -# Restart a service -overmind restart backend -overmind restart frontend - -# Stop a specific service -overmind stop backend - -# View processes -overmind ps -``` - -### View Logs - -When using overmind, all logs appear in the same terminal with color coding: -``` -backend | [log output in one color] -frontend | [log output in another color] -``` - -## Process Configuration - -The `Procfile.dev` defines what runs: - -``` -backend: cd backend && .venv/bin/python main.py -frontend: cd frontend && npm run dev -- --host -``` - -## Comparison with Old Method - -| Feature | ./dev.sh (old) | ./dev-stack.sh (new) | -|---------|----------------|----------------------| -| Start | Background processes | Foreground (better) | -| Logs | Separate files | One terminal | -| Stop | ./dev-stop.sh | Ctrl+C | -| Colors | No | Yes | -| Restart | Stop + start | overmind restart | -| Connect | Can't | overmind connect | - -## Advanced: overmind Features - -### Connect to Running Process -```bash -# Start in one terminal -./dev-stack.sh - -# In another terminal, connect to backend -overmind connect backend - -# Type in the backend process directly! -# Ctrl+B, D to disconnect (keeps running) -``` - -### Restart Individual Service -```bash -# Restart just the frontend without stopping backend -overmind restart frontend -``` - -### Environment Variables -Edit `.env` file to set ports: -``` -PORT=8000 -FRONTEND_PORT=3000 -``` - -## Troubleshooting - -### Port Already in Use -```bash -# Find and kill process on port 8000 -lsof -ti:8000 | xargs kill -9 - -# Find and kill process on port 3000 -lsof -ti:3000 | xargs kill -9 -``` - -### overmind Won't Install -If Homebrew fails, use another manager: -```bash -brew install hivemind -``` - -### Processes Won't Stop -```bash -# Kill all overmind processes -pkill overmind - -# Or use the old stop script -./dev-stop.sh -``` - -## Why This is Better - -### Before (./dev.sh): -```bash -./dev.sh -# Backend logs: logs/backend.log -# Frontend logs: logs/frontend.log -# Need to tail -f each file separately -# Hard to see errors quickly -``` - -### After (./dev-stack.sh): -```bash -./dev-stack.sh -# All logs in one terminal -# Color-coded by service -# Ctrl+C stops everything -# Easy to see errors -``` - -## Example Output - -``` -๐Ÿš€ YouMusic - Starting Development Stack -========================================= - -โœ… Using overmind (best option) - -Shortcuts: - Ctrl+C - Stop all - overmind c - Connect to services - overmind r - Restart a service - -Starting services... - -backend | INFO: Started server process [12345] -backend | INFO: Waiting for application startup. -backend | INFO: Application startup complete. -backend | INFO: Uvicorn running on http://0.0.0.0:8000 -frontend | -frontend | VITE v5.4.5 ready in 234 ms -frontend | -frontend | โžœ Local: http://localhost:3000/ -frontend | โžœ Network: http://192.168.1.10:3000/ -``` - -All in one place, color-coded, beautiful! ๐ŸŽจ - -## Summary - -**Old way:** -```bash -./dev.sh # Start in background -tail -f logs/*.log # View logs separately -./dev-stop.sh # Stop -``` - -**New way:** -```bash -./dev-stack.sh # Start, view logs, stop with Ctrl+C -``` - -Much simpler! ๐Ÿš€ diff --git a/PROJECT_SUMMARY.md b/PROJECT_SUMMARY.md deleted file mode 100644 index 8e4a369..0000000 --- a/PROJECT_SUMMARY.md +++ /dev/null @@ -1,324 +0,0 @@ -# YouMusic - Project Summary - -## ๐Ÿ“‹ Project Overview - -YouMusic is a modern, full-stack web music player with download capabilities, inspired by xiaomusic and spotube. It's designed with a mobile-first approach using React + shadcn/ui for the frontend and Python FastAPI for the backend. - -## โœ… Implemented Features - -### 1. Core Music Player โœ“ -- Play/pause controls -- Skip forward/backward -- Volume control with mute -- Progress bar with seeking -- Display current track info -- Queue management -- Auto-play next track - -### 2. Music Library Management โœ“ -- View all downloaded music -- Search local library by name/artist -- Sort and filter options -- Metadata display (title, artist, album, duration) -- File scanning functionality -- Upload music files - -### 3. Online Music Search โœ“ -- Search YouTube for music -- Search Bilibili for music -- Combined search across platforms -- Display thumbnails and metadata -- Filter by source (YouTube/Bilibili) - -### 4. Download Functionality โœ“ -- Download from YouTube URLs -- Download from Bilibili URLs -- Download single tracks -- Download entire playlists -- Background download processing -- Automatic metadata extraction -- Progress tracking support - -### 5. Playlist Management โœ“ -- Create custom playlists -- Add songs to playlists -- Remove songs from playlists -- Delete playlists -- Update playlist info -- Play entire playlists -- View playlist details - -### 6. Music Sharing โœ“ -- Share via URL parameters (?music=id) -- Direct link to specific songs -- Auto-play shared music - -### 7. Mobile-First UI โœ“ -- Responsive design -- Touch-friendly controls -- Mobile navigation -- Adaptive layouts -- Bottom player bar (mobile-friendly) - -### 8. Additional Features โœ“ -- Search by artist (shows all tracks) -- Dark mode support (via shadcn/ui) -- Toast notifications -- Loading states -- Error handling -- API documentation (FastAPI Swagger) - -## ๐Ÿ—๏ธ Architecture - -### Backend Stack -``` -FastAPI (Python) -โ”œโ”€โ”€ SQLAlchemy (ORM) -โ”œโ”€โ”€ aiosqlite (Database) -โ”œโ”€โ”€ yt-dlp (Downloader) -โ”œโ”€โ”€ mutagen (Metadata) -โ”œโ”€โ”€ aiohttp (HTTP client) -โ””โ”€โ”€ Pydantic (Validation) -``` - -### Frontend Stack -``` -React 18 + TypeScript -โ”œโ”€โ”€ Vite (Build tool) -โ”œโ”€โ”€ TanStack Query (Data fetching) -โ”œโ”€โ”€ React Router (Navigation) -โ”œโ”€โ”€ shadcn/ui (Components) -โ”œโ”€โ”€ Tailwind CSS (Styling) -โ””โ”€โ”€ Axios (API client) -``` - -## ๐Ÿ“ Project Structure - -``` -you-music/ -โ”œโ”€โ”€ backend/ -โ”‚ โ”œโ”€โ”€ app/ -โ”‚ โ”‚ โ”œโ”€โ”€ api/ # API endpoints -โ”‚ โ”‚ โ”œโ”€โ”€ core/ # Configuration -โ”‚ โ”‚ โ”œโ”€โ”€ db/ # Database -โ”‚ โ”‚ โ”œโ”€โ”€ models/ # SQLAlchemy models -โ”‚ โ”‚ โ”œโ”€โ”€ schemas/ # Pydantic schemas -โ”‚ โ”‚ โ””โ”€โ”€ services/ # Business logic -โ”‚ โ”œโ”€โ”€ main.py # FastAPI app -โ”‚ โ””โ”€โ”€ requirements.txt # Python deps -โ”œโ”€โ”€ frontend/ -โ”‚ โ”œโ”€โ”€ src/ -โ”‚ โ”‚ โ”œโ”€โ”€ components/ # React components -โ”‚ โ”‚ โ”œโ”€โ”€ api/ # API client -โ”‚ โ”‚ โ”œโ”€โ”€ hooks/ # Custom hooks -โ”‚ โ”‚ โ”œโ”€โ”€ lib/ # Utils -โ”‚ โ”‚ โ””โ”€โ”€ types/ # TypeScript types -โ”‚ โ””โ”€โ”€ package.json # Node deps -โ”œโ”€โ”€ data/ # Runtime data -โ”œโ”€โ”€ Dockerfile # Container image -โ”œโ”€โ”€ docker-compose.yml # Docker setup -โ””โ”€โ”€ README.md # Documentation -``` - -## ๐Ÿ”Œ API Endpoints - -### Music -- `GET /api/music/` - List all music -- `GET /api/music/search` - Search music -- `GET /api/music/{id}` - Get music details -- `PUT /api/music/{id}` - Update metadata -- `DELETE /api/music/{id}` - Delete music -- `POST /api/music/upload` - Upload file -- `POST /api/music/scan` - Scan directory - -### Playlists -- `GET /api/playlists/` - List playlists -- `POST /api/playlists/` - Create playlist -- `GET /api/playlists/{id}` - Get playlist -- `PUT /api/playlists/{id}` - Update playlist -- `DELETE /api/playlists/{id}` - Delete playlist -- `POST /api/playlists/{id}/music/{music_id}` - Add song -- `DELETE /api/playlists/{id}/music/{music_id}` - Remove song - -### Download -- `POST /api/download/music` - Download track -- `POST /api/download/playlist` - Download playlist -- `GET /api/download/status` - Download status - -### Search -- `GET /api/search/` - Search all sources -- `GET /api/search/youtube` - Search YouTube -- `GET /api/search/bilibili` - Search Bilibili - -## ๐Ÿš€ Deployment - -### Using Docker -```bash -docker-compose up -d -``` - -### Manual Deployment -```bash -# Backend -cd backend -pip install -r requirements.txt -uvicorn main:app --host 0.0.0.0 --port 8000 - -# Frontend -cd frontend -npm install -npm run build -``` - -## ๐ŸŽจ UI Components (shadcn/ui) - -Implemented components: -- Button -- Input -- Slider -- Card (via Tailwind) -- Toast notifications (sonner) -- Navigation -- Player controls - -## ๐Ÿ“Š Database Schema - -### Music Table -- id, title, artist, album -- duration, file_path, file_size -- source_url, source_type -- thumbnail, lyrics -- created_at, updated_at - -### Playlist Table -- id, name, description -- thumbnail -- created_at, updated_at - -### playlist_music (Many-to-Many) -- playlist_id, music_id -- position, added_at - -## ๐Ÿ” Security Features - -- Input validation (Pydantic) -- SQL injection protection (SQLAlchemy) -- XSS protection (React) -- CORS configuration -- Safe file path handling -- URL validation - -## ๐ŸŽฏ xiaomusic Integration - -Adapted from xiaomusic: -1. **Download Logic** - Using yt-dlp similar to xiaomusic -2. **Metadata Extraction** - Using mutagen library -3. **File Organization** - Directory structure handling -4. **Playlist Processing** - Batch download support -5. **FFmpeg Integration** - Audio processing - -## ๐ŸŒŸ Unique Features - -Improvements over xiaomusic: -1. Modern React UI -2. Real-time search -3. Better mobile support -4. RESTful API -5. Database-backed library -6. Shareable links -7. Progressive Web App ready - -## ๐Ÿ“ฑ Mobile Optimizations - -- Touch-friendly buttons (min 44px) -- Responsive grid layouts -- Mobile navigation -- Bottom player bar -- Swipe gestures support -- Viewport optimized - -## ๐Ÿ”„ State Management - -- TanStack Query for server state -- React useState for local state -- Audio ref for player state -- URL params for deep linking - -## ๐Ÿงช Testing Ready - -Structure supports: -- Backend: pytest -- Frontend: Vitest/Jest -- E2E: Playwright/Cypress -- API: FastAPI TestClient - -## ๐Ÿ“ˆ Performance - -- Lazy loading -- Code splitting (Vite) -- Image optimization -- Database indexing -- Async operations -- Caching (TanStack Query) - -## ๐Ÿ”ฎ Future Enhancements - -Possible additions: -- [ ] User authentication -- [ ] Multi-user support -- [ ] Audio visualization -- [ ] Lyrics display -- [ ] Equalizer -- [ ] Podcast support -- [ ] Import from Spotify -- [ ] PWA offline mode -- [ ] WebSocket for real-time updates -- [ ] Recommendation engine - -## ๐Ÿ“ฆ Dependencies - -### Key Backend Packages -- fastapi==0.115.0 -- uvicorn==0.30.6 -- sqlalchemy==2.0.35 -- yt-dlp==2024.10.7 -- mutagen==1.47.0 -- aiofiles==24.1.0 - -### Key Frontend Packages -- react==18.3.1 -- @tanstack/react-query==5.56.2 -- react-router-dom==6.26.2 -- tailwindcss==3.4.11 -- lucide-react==0.441.0 - -## ๐ŸŽ“ Learning Resources - -The project demonstrates: -- FastAPI async patterns -- React hooks usage -- TypeScript best practices -- Database modeling -- API design -- Docker containerization -- Component architecture -- State management - -## ๐Ÿ“„ License - -MIT License - Free to use and modify - -## ๐Ÿ™ Acknowledgments - -- xiaomusic - Download logic inspiration -- spotube - UI/UX inspiration -- shadcn/ui - Component library -- yt-dlp - Download engine -- FastAPI - Backend framework -- React - Frontend library - ---- - -**Status**: โœ… Complete and Ready for Use -**Version**: 1.0.0 -**Last Updated**: 2024-10-30 diff --git a/README.md b/README.md index 9ee0cf0..96ec3db 100644 --- a/README.md +++ b/README.md @@ -94,13 +94,13 @@ docker-compose up -d 1. **Create Python virtual environment** ```bash cd backend -python -m venv venv -source venv/bin/activate # On Windows: venv\Scripts\activate +uv venv --python 3.13 +source .venv/bin/activate # On Windows: .venv\Scripts\activate ``` 2. **Install dependencies** ```bash -pip install -r requirements.txt +uv sync ``` 3. **Install system dependencies** diff --git a/STRUCTURE.md b/STRUCTURE.md index 8dc04ab..9f094e0 100644 --- a/STRUCTURE.md +++ b/STRUCTURE.md @@ -13,7 +13,7 @@ you-music/ โ”‚ โ”œโ”€โ”€ backend/ # Python FastAPI backend โ”‚ โ”œโ”€โ”€ .env.example # Environment variables example -โ”‚ โ”œโ”€โ”€ requirements.txt # Python dependencies +โ”‚ โ”œโ”€โ”€ pyproject.toml # Python dependencies (uv) โ”‚ โ”œโ”€โ”€ main.py # FastAPI application entry โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ app/ @@ -116,7 +116,7 @@ you-music/ ### Backend (`backend/`) - **main.py**: FastAPI application initialization, CORS setup, route mounting -- **requirements.txt**: All Python package dependencies +- **pyproject.toml**: All Python package dependencies (managed by uv) #### Core (`backend/app/core/`) - **config.py**: Application settings using Pydantic Settings diff --git a/TESTING.md b/TESTING.md deleted file mode 100644 index fd45d26..0000000 --- a/TESTING.md +++ /dev/null @@ -1,101 +0,0 @@ -# Testing Guide - -## Backend Tests (Python) - -### Setup -```bash -cd backend -uv pip install pytest pytest-asyncio -``` - -### Run All Tests -```bash -pytest -``` - -### Run Specific Test File -```bash -pytest tests/test_artist_normalization.py -``` - -### Run With Verbose Output -```bash -pytest -v -``` - -### Run Specific Test -```bash -pytest tests/test_artist_normalization.py::TestArtistNormalization::test_multiple_artists_slash_separator -``` - -## Frontend Tests (TypeScript/Jest) - -### Setup -```bash -cd frontend -npm install -``` - -### Run All Tests -```bash -npm test -``` - -### Run Specific Test File -```bash -npm test utils.test.ts -``` - -### Run Tests in Watch Mode -```bash -npm test -- --watch -``` - -## What's Tested - -### Artist Normalization (`test_artist_normalization.py`) -- Single artist names -- Multiple artists with / separator -- Multiple artists with , separator -- Mixed separators -- Whitespace cleanup -- Unicode characters (Chinese, special chars) -- Real-world examples from database -- All artists are preserved (not just first one) - -### Artist Display Formatting (`utils.test.ts`) -- Display all artists when space permits -- Smart truncation: "FirstArtist, +N" -- Single vs multiple artist handling -- Edge cases (very short maxLength) -- Real-world player scenarios - -## Continuous Integration - -Add to your CI/CD pipeline: - -```yaml -# Backend -- cd backend && pytest - -# Frontend -- cd frontend && npm test -- --ci -``` - -## Writing New Tests - -### Backend -```python -def test_your_feature(): - """Test description""" - result = function_to_test(input) - assert result == expected_output -``` - -### Frontend -```typescript -test('description', () => { - const result = functionToTest(input) - expect(result).toBe(expectedOutput) -}) -``` diff --git a/UNIT_TESTS.md b/UNIT_TESTS.md deleted file mode 100644 index dfd5383..0000000 --- a/UNIT_TESTS.md +++ /dev/null @@ -1,177 +0,0 @@ -# Unit Tests Added - -## Overview - -Comprehensive unit tests have been added for the multi-artist name handling logic to ensure correct behavior and prevent regressions when making changes. - -## Test Files Created - -### Backend Tests (Python/pytest) - -**File:** `backend/tests/test_artist_normalization.py` - -**Coverage:** -- `normalize_artist_name()` function -- `Music.artist_list` property -- `Music.display_artist` property - -**Test Cases:** -1. Single artist names (should remain unchanged) -2. Multiple artists with `/` separator (converted to `, `) -3. Multiple artists with `,` separator (standardized spacing) -4. Mixed separators (both `/` and `,`) -5. Extra whitespace cleanup -6. Empty and Unknown values -7. Real-world examples from database -8. Preservation of ALL artists (not just first) -9. Special characters in names (dots, apostrophes) -10. Unicode characters (Chinese, accented chars) - -**Total Test Cases:** 20+ individual tests - -### Frontend Tests (TypeScript/Vitest) - -**File:** `frontend/src/lib/__tests__/utils.test.ts` - -**Coverage:** -- `formatArtist()` function - -**Test Cases:** -1. Basic functionality (null, undefined, unknown) -2. Single artist display -3. Multiple artist display -4. Smart truncation: "FirstArtist, +N" -5. Edge cases (very short maxLength) -6. Real-world player scenarios -7. Consistency with backend normalization -8. Special characters and unicode - -**Total Test Cases:** 25+ individual tests - -## Configuration Files - -### Backend -- `backend/pytest.ini` - pytest configuration -- Updated `backend/pyproject.toml` - added pytest dev dependencies - -### Frontend -- `frontend/vitest.config.ts` - Vitest configuration -- `frontend/src/lib/__tests__/` - test directory - -### Documentation -- `TESTING.md` - Complete testing guide - -## Running Tests - -### Backend (Quick Start) -```bash -cd backend -uv pip install pytest pytest-asyncio -pytest tests/test_artist_normalization.py -v -``` - -### Frontend (Setup Required) -```bash -cd frontend -npm install --save-dev vitest jsdom @testing-library/react @testing-library/jest-dom -npm test -``` - -## Example Test Output - -### Backend -``` -tests/test_artist_normalization.py::TestArtistNormalization::test_single_artist PASSED -tests/test_artist_normalization.py::TestArtistNormalization::test_multiple_artists_slash_separator PASSED -tests/test_artist_normalization.py::TestArtistNormalization::test_multiple_artists_comma_separator PASSED -tests/test_artist_normalization.py::TestArtistNormalization::test_preserves_all_artists PASSED -... -======================== 20 passed in 0.15s ======================== -``` - -### Frontend -``` - โœ“ formatArtist > Basic functionality > returns "Unknown Artist" for null - โœ“ formatArtist > Multiple artists display > shows "FirstArtist, +N" format - โœ“ formatArtist > Real-world examples > handles 6 artists with limited space -... - Test Files 1 passed (1) - Tests 25 passed (25) -``` - -## Test Examples - -### Backend Example -```python -def test_multiple_artists_slash_separator(self): - """Artists separated by / should be converted to comma-space""" - assert normalize_artist_name("่’‹ๆ˜Ž/ๅ†ฌๅญ/ๅˆ˜ไธœๆ˜Ž") == "่’‹ๆ˜Ž, ๅ†ฌๅญ, ๅˆ˜ไธœๆ˜Ž" - assert normalize_artist_name("Calvin Harris/John Newman") == "Calvin Harris, John Newman" -``` - -### Frontend Example -```typescript -test('shows "FirstArtist, +N" format when space is limited', () => { - expect(formatArtist('่’‹ๆ˜Ž, ๅ†ฌๅญ, ๅˆ˜ไธœๆ˜Ž', 10)).toBe('่’‹ๆ˜Ž, +2') - expect(formatArtist('A, B, C, D, E', 8)).toBe('A, +4') -}) -``` - -## Benefits - -โœ… **Confidence in changes** - Modify code knowing tests will catch breaks -โœ… **Documentation** - Tests show expected behavior clearly -โœ… **Regression prevention** - Catch bugs before deployment -โœ… **Refactoring safety** - Change implementation without fear -โœ… **Real-world coverage** - Tests use actual data from the music library -โœ… **Edge case handling** - Tests cover unusual but possible scenarios - -## Key Test Scenarios Covered - -### Multi-Artist Handling -- โœ… "่’‹ๆ˜Ž/ๅ†ฌๅญ/ๅˆ˜ไธœๆ˜Ž" โ†’ "่’‹ๆ˜Ž, ๅ†ฌๅญ, ๅˆ˜ไธœๆ˜Ž" -- โœ… "Justin Timberlake/Carey Mulligan/Stark Sands" โ†’ "Justin Timberlake, Carey Mulligan, Stark Sands" -- โœ… All artists preserved (not just first) -- โœ… Consistent separator (always ", ") - -### Display Formatting -- โœ… Full display when space permits -- โœ… "่’‹ๆ˜Ž, +5" when limited to 10 characters -- โœ… Smart truncation algorithm -- โœ… Edge cases (very short limits) - -## Next Steps - -1. **Install dependencies** (if not already done) -2. **Run tests** to verify everything passes -3. **Add to CI/CD** pipeline for automated testing -4. **Write new tests** when adding features -5. **Update tests** when changing behavior - -## CI/CD Integration - -Add to your GitHub Actions or CI pipeline: - -```yaml -# .github/workflows/test.yml -- name: Run Backend Tests - run: | - cd backend - uv pip install pytest pytest-asyncio - pytest - -- name: Run Frontend Tests - run: | - cd frontend - npm ci - npm test -- --ci -``` - -## Maintenance - -- **Add tests** for new features before implementing -- **Update tests** when requirements change -- **Run tests** before committing changes -- **Review coverage** periodically to find gaps - -The tests ensure the multi-artist feature works correctly and will continue to work as the codebase evolves! diff --git a/UV_MIGRATION.md b/UV_MIGRATION.md deleted file mode 100644 index 101bc5e..0000000 --- a/UV_MIGRATION.md +++ /dev/null @@ -1,148 +0,0 @@ -# Python 3.13 + uv Migration Guide - -## What Changed - -We've migrated the project to: -- โœ… **Python 3.13** (from 3.10+) -- โœ… **uv** for package management (much faster than pip) -- โœ… `.venv` directory (instead of `venv`) - -## Why uv? - -**uv** is a blazing-fast Python package installer written in Rust: -- ๐Ÿš€ **10-100x faster** than pip -- ๐Ÿ“ฆ Better dependency resolution -- ๐Ÿ”’ More reliable installs -- ๐Ÿ’พ Smaller disk usage - -## Installation - -### Install Python 3.13 - -**macOS:** -```bash -brew install python@3.13 -``` - -**Ubuntu/Debian:** -```bash -sudo apt-get update -sudo apt-get install python3.13 python3.13-venv -``` - -### Install uv (Auto-installed by setup script) - -Or manually: -```bash -curl -LsSf https://astral.sh/uv/install.sh | sh -``` - -## Usage - -### First Time Setup -```bash -./dev-setup.sh -``` - -This now: -1. Checks for Python 3.13 -2. Installs uv if needed -3. Creates `.venv` with Python 3.13 -4. Installs dependencies with uv (fast!) - -### Manual Commands - -**Create virtual environment:** -```bash -cd backend -uv venv --python 3.13 -``` - -**Install dependencies:** -```bash -uv pip install -r requirements.txt -``` - -**Add a new package:** -```bash -uv pip install package-name -uv pip freeze > requirements.txt -``` - -**Activate environment:** -```bash -source .venv/bin/activate -``` - -## Troubleshooting - -### "python3.13: command not found" -Install Python 3.13 first: -```bash -brew install python@3.13 # macOS -``` - -### "uv: command not found" -The setup script will install it, or install manually: -```bash -curl -LsSf https://astral.sh/uv/install.sh | sh -export PATH="$HOME/.cargo/bin:$PATH" -``` - -### Existing venv Issues -Remove old virtual environment: -```bash -rm -rf backend/venv backend/.venv -./dev-setup.sh -``` - -### PyO3 Version Errors -This was the issue with Python 3.14 - now fixed by using Python 3.13 which is fully supported by all dependencies. - -## Benefits - -### Speed Comparison - -| Operation | pip | uv | -|-----------|-----|-----| -| Install all deps | 45s | 2s | -| Single package | 3s | 0.3s | -| Resolve deps | 8s | 0.5s | - -### Disk Space - -uv uses a global cache, saving disk space: -- pip: Each venv has full copies -- uv: Shared cache across projects - -## Migration Steps (Already Done) - -If you had the old setup: - -1. Stop servers: `./dev-stop.sh` -2. Remove old venv: `rm -rf backend/venv` -3. Run new setup: `./dev-setup.sh` -4. Start servers: `./dev.sh` - -## Files Updated - -- โœ… `dev-setup.sh` - Uses Python 3.13 and uv -- โœ… `dev-backend.sh` - Uses `.venv` -- โœ… `dev.sh` - Checks for `.venv` -- โœ… `requirements.txt` - Updated dependencies -- โœ… `pyproject.toml` - Added for uv -- โœ… All documentation updated - -## Resources - -- uv docs: https://github.com/astral-sh/uv -- Python 3.13: https://docs.python.org/3.13/ - -## Summary - -You can now run: -```bash -./dev-setup.sh && ./dev.sh -``` - -Everything will work faster! ๐Ÿš€ diff --git a/VERIFICATION_COMPLETE.md b/VERIFICATION_COMPLETE.md index c748d66..2c51690 100644 --- a/VERIFICATION_COMPLETE.md +++ b/VERIFICATION_COMPLETE.md @@ -60,7 +60,7 @@ ### 1. Backend Dependencies **Problem**: Missing `greenlet` library for SQLAlchemy async -**Solution**: Added `greenlet==3.1.1` to requirements.txt +**Solution**: Added `greenlet>=3.1.1` to pyproject.toml ### 2. Frontend Config **Problem**: CommonJS syntax in ES module project diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 6887908..56ff076 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -18,16 +18,16 @@ dependencies = [ "python-jose[cryptography]>=3.3.0", "pydantic>=2.9.2", "pydantic-settings>=2.5.2", - "sqlalchemy>=2.0.35", + "sqlalchemy[asyncio]>=2.0.35", "aiosqlite>=0.20.0", + "greenlet>=3.1.1", "alembic>=1.17.1", "apscheduler>=3.10.4", "httpx>=0.28.1", ] -[tool.uv] -dev-dependencies = [ +[dependency-groups] +dev = [ "pytest>=8.0.0", "pytest-asyncio>=0.23.0", ] - diff --git a/backend/requirements.txt b/backend/requirements.txt deleted file mode 100644 index 886f1a0..0000000 --- a/backend/requirements.txt +++ /dev/null @@ -1,16 +0,0 @@ -fastapi==0.115.0 -uvicorn[standard]==0.30.6 -python-multipart==0.0.12 -aiofiles==24.1.0 -aiohttp==3.10.5 -yt-dlp==2025.10.22 -mutagen==1.47.0 -pillow==10.4.0 -python-jose[cryptography]==3.3.0 -pydantic==2.9.2 -pydantic-settings==2.5.2 -sqlalchemy[asyncio]==2.0.35 -aiosqlite==0.20.0 -greenlet==3.1.1 -apscheduler==3.10.4 -alembic==1.17.1 diff --git a/backend/uv.lock b/backend/uv.lock index b7b8165..ceff7a6 100644 --- a/backend/uv.lock +++ b/backend/uv.lock @@ -374,6 +374,30 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, ] +[[package]] +name = "greenlet" +version = "3.2.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/03/b8/704d753a5a45507a7aab61f18db9509302ed3d0a27ac7e0359ec2905b1a6/greenlet-3.2.4.tar.gz", hash = "sha256:0dca0d95ff849f9a364385f36ab49f50065d76964944638be9691e1832e9f86d", size = 188260, upload-time = "2025-08-07T13:24:33.51Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/e8/58c7f85958bda41dafea50497cbd59738c5c43dbbea5ee83d651234398f4/greenlet-3.2.4-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31", size = 272814, upload-time = "2025-08-07T13:15:50.011Z" }, + { url = "https://files.pythonhosted.org/packages/62/dd/b9f59862e9e257a16e4e610480cfffd29e3fae018a68c2332090b53aac3d/greenlet-3.2.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945", size = 641073, upload-time = "2025-08-07T13:42:57.23Z" }, + { url = "https://files.pythonhosted.org/packages/f7/0b/bc13f787394920b23073ca3b6c4a7a21396301ed75a655bcb47196b50e6e/greenlet-3.2.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:710638eb93b1fa52823aa91bf75326f9ecdfd5e0466f00789246a5280f4ba0fc", size = 655191, upload-time = "2025-08-07T13:45:29.752Z" }, + { url = "https://files.pythonhosted.org/packages/f2/d6/6adde57d1345a8d0f14d31e4ab9c23cfe8e2cd39c3baf7674b4b0338d266/greenlet-3.2.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c5111ccdc9c88f423426df3fd1811bfc40ed66264d35aa373420a34377efc98a", size = 649516, upload-time = "2025-08-07T13:53:16.314Z" }, + { url = "https://files.pythonhosted.org/packages/7f/3b/3a3328a788d4a473889a2d403199932be55b1b0060f4ddd96ee7cdfcad10/greenlet-3.2.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d76383238584e9711e20ebe14db6c88ddcedc1829a9ad31a584389463b5aa504", size = 652169, upload-time = "2025-08-07T13:18:32.861Z" }, + { url = "https://files.pythonhosted.org/packages/ee/43/3cecdc0349359e1a527cbf2e3e28e5f8f06d3343aaf82ca13437a9aa290f/greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671", size = 610497, upload-time = "2025-08-07T13:18:31.636Z" }, + { url = "https://files.pythonhosted.org/packages/b8/19/06b6cf5d604e2c382a6f31cafafd6f33d5dea706f4db7bdab184bad2b21d/greenlet-3.2.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b", size = 1121662, upload-time = "2025-08-07T13:42:41.117Z" }, + { url = "https://files.pythonhosted.org/packages/a2/15/0d5e4e1a66fab130d98168fe984c509249c833c1a3c16806b90f253ce7b9/greenlet-3.2.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae", size = 1149210, upload-time = "2025-08-07T13:18:24.072Z" }, + { url = "https://files.pythonhosted.org/packages/0b/55/2321e43595e6801e105fcfdee02b34c0f996eb71e6ddffca6b10b7e1d771/greenlet-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b", size = 299685, upload-time = "2025-08-07T13:24:38.824Z" }, + { url = "https://files.pythonhosted.org/packages/22/5c/85273fd7cc388285632b0498dbbab97596e04b154933dfe0f3e68156c68c/greenlet-3.2.4-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0", size = 273586, upload-time = "2025-08-07T13:16:08.004Z" }, + { url = "https://files.pythonhosted.org/packages/d1/75/10aeeaa3da9332c2e761e4c50d4c3556c21113ee3f0afa2cf5769946f7a3/greenlet-3.2.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f", size = 686346, upload-time = "2025-08-07T13:42:59.944Z" }, + { url = "https://files.pythonhosted.org/packages/c0/aa/687d6b12ffb505a4447567d1f3abea23bd20e73a5bed63871178e0831b7a/greenlet-3.2.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c17b6b34111ea72fc5a4e4beec9711d2226285f0386ea83477cbb97c30a3f3a5", size = 699218, upload-time = "2025-08-07T13:45:30.969Z" }, + { url = "https://files.pythonhosted.org/packages/dc/8b/29aae55436521f1d6f8ff4e12fb676f3400de7fcf27fccd1d4d17fd8fecd/greenlet-3.2.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b4a1870c51720687af7fa3e7cda6d08d801dae660f75a76f3845b642b4da6ee1", size = 694659, upload-time = "2025-08-07T13:53:17.759Z" }, + { url = "https://files.pythonhosted.org/packages/92/2e/ea25914b1ebfde93b6fc4ff46d6864564fba59024e928bdc7de475affc25/greenlet-3.2.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735", size = 695355, upload-time = "2025-08-07T13:18:34.517Z" }, + { url = "https://files.pythonhosted.org/packages/72/60/fc56c62046ec17f6b0d3060564562c64c862948c9d4bc8aa807cf5bd74f4/greenlet-3.2.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337", size = 657512, upload-time = "2025-08-07T13:18:33.969Z" }, + { url = "https://files.pythonhosted.org/packages/e3/a5/6ddab2b4c112be95601c13428db1d8b6608a8b6039816f2ba09c346c08fc/greenlet-3.2.4-cp314-cp314-win_amd64.whl", hash = "sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01", size = 303425, upload-time = "2025-08-07T13:32:27.59Z" }, +] + [[package]] name = "h11" version = "0.16.0" @@ -442,6 +466,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, ] +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + [[package]] name = "mako" version = "1.3.10" @@ -596,6 +629,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b0/7a/620f945b96be1f6ee357d211d5bf74ab1b7fe72a9f1525aafbfe3aee6875/mutagen-1.47.0-py3-none-any.whl", hash = "sha256:edd96f50c5907a9539d8e5bba7245f62c9f520aef333d13392a79a4f70aca719", size = 194391, upload-time = "2023-09-03T16:33:29.955Z" }, ] +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + [[package]] name = "pillow" version = "10.4.0" @@ -615,6 +657,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/48/2c/2e0a52890f269435eee38b21c8218e102c621fe8d8df8b9dd06fabf879ba/pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d", size = 2243375, upload-time = "2024-07-01T09:47:09.065Z" }, ] +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + [[package]] name = "propcache" version = "0.4.1" @@ -779,6 +830,43 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/29/8d/29e82e333f32d9e2051c10764b906c2a6cd140992910b5f49762790911ba/pydantic_settings-2.5.2-py3-none-any.whl", hash = "sha256:2c912e55fd5794a59bf8c832b9de832dcfdf4778d79ff79b708744eed499a907", size = 26864, upload-time = "2024-09-11T09:08:07.242Z" }, ] +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pytest" +version = "8.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" }, +] + +[[package]] +name = "pytest-asyncio" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/86/9e3c5f48f7b7b638b216e4b9e645f54d199d7abbbab7a64a13b4e12ba10f/pytest_asyncio-1.2.0.tar.gz", hash = "sha256:c609a64a2a8768462d0c99811ddb8bd2583c33fd33cf7f21af1c142e824ffb57", size = 50119, upload-time = "2025-09-12T07:33:53.816Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl", hash = "sha256:8e17ae5e46d8e7efe51ab6494dd2010f4ca8dae51652aa3c8d55acf50bfb2e99", size = 15095, upload-time = "2025-09-12T07:33:52.639Z" }, +] + [[package]] name = "python-dotenv" version = "1.2.1" @@ -903,6 +991,11 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0e/c6/33c706449cdd92b1b6d756b247761e27d32230fd6b2de5f44c4c3e5632b2/SQLAlchemy-2.0.35-py3-none-any.whl", hash = "sha256:2ab3f0336c0387662ce6221ad30ab3a5e6499aab01b9790879b6578fd9b8faa1", size = 1881276, upload-time = "2024-09-16T23:14:28.324Z" }, ] +[package.optional-dependencies] +asyncio = [ + { name = "greenlet" }, +] + [[package]] name = "starlette" version = "0.49.1" @@ -1173,6 +1266,7 @@ dependencies = [ { name = "alembic" }, { name = "apscheduler" }, { name = "fastapi" }, + { name = "greenlet" }, { name = "httpx" }, { name = "mutagen" }, { name = "pillow" }, @@ -1180,11 +1274,17 @@ dependencies = [ { name = "pydantic-settings" }, { name = "python-jose", extra = ["cryptography"] }, { name = "python-multipart" }, - { name = "sqlalchemy" }, + { name = "sqlalchemy", extra = ["asyncio"] }, { name = "uvicorn", extra = ["standard"] }, { name = "yt-dlp" }, ] +[package.dev-dependencies] +dev = [ + { name = "pytest" }, + { name = "pytest-asyncio" }, +] + [package.metadata] requires-dist = [ { name = "aiofiles", specifier = ">=24.1.0" }, @@ -1193,6 +1293,7 @@ requires-dist = [ { name = "alembic", specifier = ">=1.17.1" }, { name = "apscheduler", specifier = ">=3.10.4" }, { name = "fastapi", specifier = ">=0.115.0" }, + { name = "greenlet", specifier = ">=3.1.1" }, { name = "httpx", specifier = ">=0.28.1" }, { name = "mutagen", specifier = ">=1.47.0" }, { name = "pillow", specifier = ">=10.4.0" }, @@ -1200,13 +1301,16 @@ requires-dist = [ { name = "pydantic-settings", specifier = ">=2.5.2" }, { name = "python-jose", extras = ["cryptography"], specifier = ">=3.3.0" }, { name = "python-multipart", specifier = ">=0.0.12" }, - { name = "sqlalchemy", specifier = ">=2.0.35" }, + { name = "sqlalchemy", extras = ["asyncio"], specifier = ">=2.0.35" }, { name = "uvicorn", extras = ["standard"], specifier = ">=0.30.6" }, { name = "yt-dlp", specifier = ">=2025.10.22" }, ] [package.metadata.requires-dev] -dev = [] +dev = [ + { name = "pytest", specifier = ">=8.0.0" }, + { name = "pytest-asyncio", specifier = ">=0.23.0" }, +] [[package]] name = "yt-dlp" diff --git a/dev-setup.sh b/dev-setup.sh index 58a451c..a9a9e66 100755 --- a/dev-setup.sh +++ b/dev-setup.sh @@ -90,7 +90,7 @@ if [ ! -d ".venv" ]; then fi echo "Installing Python dependencies with uv..." -uv pip install -r requirements.txt +uv sync echo -e "${GREEN}โœ… Backend setup complete${NC}" diff --git a/dev-stack.sh b/dev-stack.sh index bacbcae..e049f35 100755 --- a/dev-stack.sh +++ b/dev-stack.sh @@ -87,10 +87,8 @@ if [ ! -d "backend/.venv" ]; then fi # Install/update Python dependencies -echo "Installing Python dependencies..." -cd backend -source .venv/bin/activate -uv pip install -r requirements.txt +echo "Installing Python dependencies with uv..." +uv sync cd .. # Create backend .env if needed diff --git a/setup.sh b/setup.sh index b80699d..6e94bb6 100755 --- a/setup.sh +++ b/setup.sh @@ -54,12 +54,18 @@ else echo "๐Ÿ”ง Setting up backend..." cd backend - if [ ! -d "venv" ]; then - python3 -m venv venv + # Check if uv is installed + if ! command -v uv &> /dev/null; then + echo "Installing uv..." + curl -LsSf https://astral.sh/uv/install.sh | sh + export PATH="$HOME/.cargo/bin:$PATH" fi - source venv/bin/activate - pip install -r requirements.txt + if [ ! -d ".venv" ]; then + uv venv --python 3.13 + fi + + uv sync # Create data directories mkdir -p ../data/music ../data/uploads ../data/temp