# AGENTS.md - AI/LLM Context Guide This document provides context for AI agents and LLMs to understand and work with the YouMusic project effectively. ## Project Overview **YouMusic** is a modern, full-stack web music player with download capabilities. It allows users to search, download, and play music from YouTube and Bilibili, manage playlists, and share music links. ### Technology Stack - **Backend**: Python 3.13, FastAPI, SQLAlchemy (async), yt-dlp, mutagen, uv (package manager) - **Frontend**: React 18, TypeScript, Vite, TanStack Query, shadcn/ui, Tailwind CSS - **Database**: SQLite with aiosqlite (async driver) - **Deployment**: Docker Compose, or local development scripts ### Project Type - Full-stack web application - Single-page application (SPA) - REST API backend - Mobile-first responsive design - Single-user, no authentication ## Architecture ### Backend (FastAPI) ``` backend/ ├── main.py # Entry point, FastAPI app initialization └── app/ ├── api/ # REST API endpoints │ ├── music.py # Music CRUD operations │ ├── playlist.py # Playlist management │ ├── download.py # Download from YouTube/Bilibili │ └── search.py # Search online sources ├── core/ │ └── config.py # Settings using Pydantic ├── db/ │ └── session.py # SQLAlchemy async setup ├── models/ │ └── models.py # Music, Playlist, associations ├── schemas/ │ └── schemas.py # Pydantic request/response models └── services/ ├── downloader.py # yt-dlp music download logic └── search.py # YouTube/Bilibili search ``` **Key Backend Concepts:** - Async/await throughout for performance - Background tasks for downloads - RESTful API design - Auto-generated OpenAPI/Swagger docs at `/docs` - CORS enabled for frontend communication ### Frontend (React) ``` frontend/src/ ├── main.tsx # React app entry, providers ├── App.tsx # Main app, routing, player state ├── components/ │ ├── ui/ # shadcn/ui components │ ├── player/ # Music player │ ├── search/ # Search interface │ └── playlist/ # Playlist management ├── api/ │ └── client.ts # Axios API client ├── lib/ │ └── utils.ts # Helper functions └── types/ └── index.ts # TypeScript interfaces ``` **Key Frontend Concepts:** - Component-based architecture - TanStack Query for server state - React Router for navigation - shadcn/ui for accessible components - Mobile-first responsive design - Hot module replacement (HMR) in dev ## Database Schema **⚠️ IMPORTANT: Database Migrations** This project uses **Alembic** for database migrations. When modifying database schema: 1. Never delete the database in production 2. Always create migrations: `cd backend && ./migrate.sh create "description"` 3. Review the generated migration in `alembic/versions/` 4. Apply with: `./migrate.sh upgrade` 5. See [MIGRATIONS.md](MIGRATIONS.md) for complete guide Migrations run automatically on app startup, so existing deployments will auto-upgrade. ### Tables **music** - `id`: Primary key - `title`: Song name - `artist`: Artist/singer name (nullable) - `album`: Album name (nullable) - `duration`: Length in seconds (nullable) - `file_path`: Relative path to audio file - `file_size`: File size in bytes - `source_url`: Original download URL (nullable) - `source_type`: "youtube", "bilibili", "local", "upload" - `thumbnail`: Image URL (nullable) - `lyrics`: Song lyrics (nullable) - `created_at`, `updated_at`: Timestamps **playlists** - `id`: Primary key - `name`: Playlist name (unique) - `description`: Playlist description (nullable) - `thumbnail`: Playlist image (nullable) - `created_at`, `updated_at`: Timestamps **playlist_music** (Many-to-Many) - `playlist_id`: Foreign key to playlists - `music_id`: Foreign key to music - `position`: Order in playlist - `added_at`: Timestamp ### Relationships - One playlist has many music items - One music item can be in many playlists ## API Endpoints ### Music API (`/api/music/`) - `GET /` - List all music - `GET /search?q={query}` - Search local library - `GET /{id}` - Get music by ID - `GET /artist/{name}` - Get all music by artist - `PUT /{id}` - Update metadata - `DELETE /{id}` - Delete music and file - `POST /upload` - Upload music file - `POST /scan` - Scan directory for new files ### Playlist API (`/api/playlists/`) - `GET /` - List all playlists - `POST /` - Create playlist - `GET /{id}` - Get playlist with songs - `GET /name/{name}` - Get playlist by name - `PUT /{id}` - Update playlist - `DELETE /{id}` - Delete playlist - `POST /{id}/music/{music_id}` - Add song - `DELETE /{id}/music/{music_id}` - Remove song ### Download API (`/api/download/`) - `POST /music` - Download single track (background task) - `POST /playlist` - Download entire playlist (background task) - `GET /status` - Download queue status ### Search API (`/api/search/`) - `GET /?q={query}&source={all|youtube|bilibili}` - Search online - `GET /youtube?q={query}` - Search YouTube only - `GET /bilibili?q={query}` - Search Bilibili only ## Core Features ### 1. Music Download (from xiaomusic) The download logic is adapted from [xiaomusic](https://github.com/hanxi/xiaomusic) using `yt-dlp`: ```python # Core download command yt-dlp --no-playlist -x --audio-format mp3 \ --audio-quality 0 --paths {music_dir} \ -o "{title}.%(ext)s" {url} ``` **Supported sources:** - YouTube videos and playlists - Bilibili videos - Any site supported by yt-dlp ### 2. Music Player - HTML5 audio element - Play/pause, skip forward/back - Volume control with mute - Progress bar with seeking - Auto-play next in queue - Display current track info ### 3. Search - **Local**: SQLAlchemy LIKE queries on title/artist - **Online**: yt-dlp JSON dump for YouTube, Bilibili API for Bilibili - Combined results with thumbnails - Artist-based filtering ### 4. Playlists - Create, read, update, delete - Add/remove songs - Play entire playlist - Maintain song order ### 5. Music Sharing - Share via URL: `/?music={id}` - Auto-load and play shared music - Deep linking support ## Development Modes ### Local Development (Fastest) ```bash ./dev-setup.sh # First time ./dev.sh # Daily development ./dev-stop.sh # Stop servers ``` **Ports:** - Frontend: http://localhost:3000 (Vite dev server) - Backend: http://localhost:8000 (uvicorn with reload) **Features:** - Hot reload for both frontend and backend - Instant file changes - Native performance - Logs in `logs/` directory ### Docker Deployment ```bash docker-compose up -d ``` **Ports:** - Combined app: http://localhost:8000 (frontend served by backend) ## File Conventions ### Backend - **Naming**: `snake_case` for files, functions, variables - **Async**: All I/O operations use `async`/`await` - **Type hints**: All functions have type hints - **Imports**: Absolute imports from `app.` ### Frontend - **Naming**: `PascalCase` for components, `camelCase` for functions/variables - **Files**: `.tsx` for components, `.ts` for utilities - **Exports**: Named exports preferred - **Hooks**: Custom hooks in `hooks/` directory ### API Communication - All endpoints return JSON - Error responses follow FastAPI conventions - Request/response validated by Pydantic schemas - CORS enabled for cross-origin requests ## Common Tasks for AI Agents ### Adding a New API Endpoint 1. **Create endpoint in `backend/app/api/`** ```python @router.get("/new-endpoint") async def new_endpoint(db: AsyncSession = Depends(get_db)): # Implementation pass ``` 2. **Add to router in `backend/main.py`** ```python app.include_router(new_router, prefix="/api/new", tags=["new"]) ``` 3. **Add API client function in `frontend/src/api/client.ts`** ```typescript export const newApi = { getItems: () => api.get('/new-endpoint'), } ``` 4. **Use in component with TanStack Query** ```typescript const { data } = useQuery({ queryKey: ['new-items'], queryFn: async () => { const response = await newApi.getItems() return response.data } }) ``` ### Adding a New UI Component 1. **Create component in `frontend/src/components/`** ```typescript export default function NewComponent({ prop }: Props) { return
...
} ``` 2. **Use shadcn/ui components** from `@/components/ui/` 3. **Add to routing in `App.tsx`** if needed 4. **Use Tailwind for styling** ### Modifying Database Schema **IMPORTANT: We use Alembic for database migrations. Never delete the database in production!** 1. **Update model in `backend/app/models/models.py`** ```python class Music(Base): # ... existing fields ... new_field: Mapped[Optional[str]] = mapped_column(String, nullable=True) ``` 2. **Create migration** ```bash cd backend ./migrate.sh create "Add new_field to music table" ``` 3. **Review generated migration** in `backend/alembic/versions/*.py` - Check auto-generated SQL is correct - Edit if needed (e.g., for renaming columns, data migrations) 4. **Apply migration** ```bash ./migrate.sh upgrade ``` 5. **Update schema in `backend/app/schemas/schemas.py`** if needed **Notes:** - Migrations run automatically on app startup - Never edit applied migrations - create new ones - Use `./migrate.sh downgrade` to rollback if needed - See [MIGRATIONS.md](MIGRATIONS.md) for complete guide ### Adding Download Source 1. **Check yt-dlp support** (most sites already supported) 2. **Add search function** in `backend/app/services/search.py` 3. **Update search endpoint** in `backend/app/api/search.py` 4. **Add UI** in `frontend/src/components/search/SearchPage.tsx` ## Environment Variables ### Backend (.env) ```env DATABASE_URL=sqlite+aiosqlite:///./data/youmusic.db MUSIC_DIR=./data/music UPLOAD_DIR=./data/uploads TEMP_DIR=./data/temp FFMPEG_LOCATION=ffmpeg PROXY=http://proxy:port # Optional ``` ### Frontend (.env) ```env VITE_API_URL=http://localhost:8000 ``` ## Testing ### Backend ```bash cd backend pytest ``` ### Frontend ```bash cd frontend npm test ``` ### API Testing - Visit http://localhost:8000/docs for interactive testing - Use curl, Postman, or Thunder Client ## Dependencies ### Key Backend Packages - `fastapi` - Web framework - `uvicorn` - ASGI server - `sqlalchemy` - ORM - `aiosqlite` - Async SQLite driver - `alembic` - Database migrations - `yt-dlp` - Universal downloader - `mutagen` - Audio metadata - `pydantic` - Data validation ### Key Frontend Packages - `react` - UI library - `@tanstack/react-query` - Data fetching - `react-router-dom` - Routing - `axios` - HTTP client - `tailwindcss` - Styling - `lucide-react` - Icons ## Code Patterns ### Backend Async Pattern ```python async def get_items(db: AsyncSession = Depends(get_db)): result = await db.execute(select(Model)) items = result.scalars().all() return items ``` ### Frontend Query Pattern ```typescript const { data, isLoading } = useQuery({ queryKey: ['items'], queryFn: async () => { const response = await api.get('/items') return response.data } }) ``` ### Error Handling ```python # Backend raise HTTPException(status_code=404, detail="Not found") # Frontend try { await api.call() toast.success('Success!') } catch (error) { toast.error('Failed!') } ``` ## Performance Considerations ### Backend - Use async for all I/O operations - Background tasks for long-running downloads - Database indexes on frequently queried fields - Limit query results with pagination ### Frontend - Lazy load components - Use TanStack Query caching - Debounce search inputs - Optimize images ## Security ### Backend - Input validation via Pydantic - SQL injection protection via SQLAlchemy - Path traversal protection in file operations - CORS configuration ### Frontend - XSS protection via React - No eval() or dangerouslySetInnerHTML - Sanitize user inputs - Secure URL parsing ## Debugging ### Backend - Check logs: `tail -f logs/backend.log` - Use print statements (shown in logs) - FastAPI auto-reloads on code changes - Test in browser: http://localhost:8000/docs ### Frontend - Check logs: `tail -f logs/frontend.log` - Browser console for errors - React DevTools for component inspection - Network tab for API calls ## Common Errors ### "Module not found" - Backend: Activate .venv, `uv sync` - Frontend: `npm install` ### "Port already in use" ```bash lsof -ti:8000 | xargs kill -9 # Backend lsof -ti:3000 | xargs kill -9 # Frontend ``` ### "FFmpeg not found" ```bash brew install ffmpeg # macOS sudo apt-get install ffmpeg # Ubuntu ``` ### "Database locked" - Only one process can write at a time - Restart backend: `./dev-stop.sh && ./dev.sh` ## AI Agent Guidelines ### When Adding Features 1. Check if dependencies are already installed 2. Follow existing code patterns 3. Update both backend and frontend if needed 4. Add type hints/types 5. Test the feature 6. Update relevant documentation ### When Debugging 1. Check logs first 2. Verify dependencies are installed 3. Ensure servers are running 4. Test API endpoints separately 5. Check browser console ### When Refactoring 1. Don't break existing features 2. Maintain async patterns 3. Keep type safety 4. Update tests if they exist 5. Follow project conventions ### Code Style - **Backend**: Follow PEP 8, use async/await - **Frontend**: Use TypeScript, functional components - **Both**: Clear variable names, comments for complex logic ## Project Goals 1. **Simplicity** - Easy to understand and modify 2. **Performance** - Fast response times, efficient queries 3. **Maintainability** - Clear structure, good documentation 4. **Mobile-First** - Responsive design, touch-friendly 5. **Single-User** - No authentication complexity ## Related Projects - **xiaomusic**: Inspired download logic and yt-dlp usage - **spotube**: UI/UX design inspiration - **shadcn/ui**: Component library - **yt-dlp**: Download engine ## Resources - FastAPI docs: https://fastapi.tiangolo.com - React docs: https://react.dev - yt-dlp: https://github.com/yt-dlp/yt-dlp - shadcn/ui: https://ui.shadcn.com - TanStack Query: https://tanstack.com/query ## Version Information - **Current Version**: 1.0.0 - **Python**: 3.13 - **uv**: Latest - **Node.js**: 18+ - **React**: 18.3.1 - **FastAPI**: 0.115.0 ## License MIT License - Free to use and modify --- **For AI Agents**: This project is well-structured, fully typed, and follows modern best practices. Feel free to suggest improvements, add features, or refactor code while maintaining the existing patterns and architecture. No need to create summary doc after made changes