Fully switch to uv and do clean up

This commit is contained in:
2025-11-03 10:54:12 +11:00
parent a74aa148dc
commit fc07c9e134
23 changed files with 149 additions and 2174 deletions
+1 -1
View File
@@ -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"
-345
View File
@@ -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! 🎵🎶🎧
-60
View File
@@ -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.
+6 -3
View File
@@ -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
+9 -6
View File
@@ -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)
-491
View File
@@ -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**
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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
-257
View File
@@ -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
-220
View File
@@ -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! 🚀
-324
View File
@@ -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
+3 -3
View File
@@ -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**
+2 -2
View File
@@ -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
-101
View File
@@ -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)
})
```
-177
View File
@@ -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!
-148
View File
@@ -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! 🚀
+1 -1
View File
@@ -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
+4 -4
View File
@@ -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",
]
-16
View File
@@ -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
+107 -3
View File
@@ -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"
+1 -1
View File
@@ -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}"
+2 -4
View File
@@ -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
+10 -4
View File
@@ -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