mirror of
https://github.com/wahyd4/you-music.git
synced 2026-08-08 20:59:47 +10:00
Fully switch to uv and do clean up
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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! 🎵🎶🎧
|
||||
@@ -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.
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
@@ -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! 🚀
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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! 🚀
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
]
|
||||
|
||||
|
||||
@@ -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
|
||||
Generated
+107
-3
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user