A self-hosted YouTube audio downloader with automatic metadata tagging.
- Search & Download — Paste a YouTube URL or search by name
- MP3 320kbps — Best quality audio extraction
- Auto-tag — Fetches artist, album, track number, year from MusicBrainz
- Cover Art — Downloads album artwork automatically
- YouTube Cookies — Optional upload to bypass rate limits
- i18n — Portuguese (PT) / English (EN) toggle
- Progress Tracking — Real-time download progress bars
- Backend: FastAPI (Python 3.11+)
- Frontend: Vanilla JS + Jinja2 templates
- Metadata: yt-dlp, MusicBrainz, mutagen
# Clone & enter git clone https://github.com/<your-username>/blackpearl.git cd blackpearl # Create venv (Python 3.11+) python3 -m venv .venv source .venv/bin/activate # Linux/macOS # .venv\Scripts\activate # Windows # Install deps pip install -r requirements.txt # Run python main.py
- Python 3.11+
- FFmpeg (for audio conversion)
- Deno (optional, for YouTube JS challenges)
Linux (apt):
sudo apt install ffmpeg
macOS (brew):
brew install ffmpeg
Windows: Download from https://ffmpeg.org (add to PATH)
Required only if YouTube returns JS challenges. Install:
curl -fsSL https://deno.land/x/install/install.sh | sh # Add ~/.deno/bin to PATH
- Open the app
- Paste a YouTube link (youtube.com/watch?v=...) or search term
- Click search
- Click download on the result
- File saves to
downloads/with ID3 tags
When enabled (default), Black Pearl tries to:
- Parse artist/track from YouTube title
- Search YouTube Music for structured metadata
- Query MusicBrainz for album/track info
- Download cover art from Cover Art Archive
- Apply ID3 tags and rename file
Disable via "Auto-tag" toggle in header.
If YouTube blocks downloads ("Sign in to confirm you're not a bot"):
- Install "Get cookies.txt LOCALLY" extension in Librewolf/Firefox
- Log into YouTube
- Export cookies
- Open Settings (gear icon) → Upload cookies.txt
Or the app auto-detects cookies from installed browsers (Firefox, Chrome, Brave, Edge, etc.).
blackpearl/
├── main.py # FastAPI backend
├── requirements.txt # Python deps
├── pyproject.toml # Project config
├── templates/
│ └── index.html # Jinja2 template
├── static/
│ ├── css/style.css # UI styles
│ └── js/app.js # Frontend logic
├── downloads/ # Downloaded files
├── cookies.txt # YouTube session (optional)
├── DESIGN.md # Design system
├── PRODUCT.md # Product brief
└── shape.md # Frontend spec
| Variable | Description | Default |
|---|---|---|
BP_DOWNLOADS_DIR |
Download folder | ./downloads |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/search |
Search YouTube |
| POST | /api/download |
Start download |
| GET | /api/progress/{task_id} |
Check progress |
| DELETE | /api/tasks/{task_id} |
Cleanup task |
| GET | /api/cookies/status |
Cookie status |
| POST | /api/cookies/upload |
Upload cookies |
| DELETE | /api/cookies |
Remove cookies |
# Production run uvicorn main:app --host 0.0.0.0 --port 8046 # Or with gunicorn pip install gunicorn gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker
MIT