fm-dlp is a CLI tool for searching YouTube/YTMusic and downloading audio/video from 1000+ platforms
Project description
fm-dlp is a CLI tool for searching YouTube/YTMusic and downloading audio/video from 1000+ platforms
Download and tag high-quality music and video from YouTube, YouTube Music, and 1000+ sites — all from your terminal.
✨ Features
- Multi-platform Search — YouTube, YouTube Music
- Search by Type — Tracks or albums
- Parallel Downloads — Async support for multiple URLs
- 1000+ Supported Sites — Any site yt-dlp supports (YouTube, SoundCloud, Bandcamp, etc.)
- Audio Formats — MP3, AAC, FLAC, M4A, Opus, Vorbis, WAV with configurable bitrate
- Video Formats — MP4, MKV, WebM, MOV, AVI, FLV with automatic audio codec selection
- Metadata Embedding — Title, artist, album tags + thumbnail (audio only)
- Proxy Support — HTTP, HTTPS, SOCKS4, SOCKS5, SOCKS5h for all requests (download supports all protocols; search via yt-music requires HTTP/HTTPS)
- Cookie Support — Browser cookies for restricted content
- Self-updating — Built-in update mechanism via Git
- Cross-platform Config — Stores config in standard app config directory (XDG, AppData, Application Support)
🚀 Quick Start
Prerequisites
- Python 3.10+ & FFmpeg & Git (Git only required for
updatecommand)
Installation
Via pip (recommended)
pip install fm-dlp
Via uv
uv pip install fm-dlp
Via pipx (isolated environment)
pipx install fm-dlp
From source (development)
git clone https://github.com/Fkernel653/fm-dlp.git && cd fm-dlp
uv (recommended)
uv sync
pip
pip install .
Poetry
poetry install
PDM
pdm install
Usage
# Set download directory (required first)
fm-dlp config ~/Music
# Search for tracks
fm-dlp search "artist name" --limit 5 --platform yt-music
# Search for albums
fm-dlp search "album name" --platform yt-music --type album
# Download audio
fm-dlp download "https://youtu.be/..." --codec mp3 --kbps 320
# Download video
fm-dlp download "https://youtu.be/..." --codec mp4
Note: If installed from source, replace
fm-dlpwithpython modules/cli.pyin all examples.
📋 Commands
search — Find music
fm-dlp search <query> [--limit 10] [--platform {yt-video|yt-music}] [--type {track|album}] [--proxy URL]
| Option | Values | Default | Description |
|---|---|---|---|
--platform |
yt-video, yt-music |
yt-music |
Search platform |
--type |
track, album |
track |
Content type to search |
--limit |
1–∞ | 10 | Number of results |
--proxy |
URL | — | Proxy for requests |
download — Download audio or video
fm-dlp download <urls> [--codec CODEC] [--kbps 256] [--quiet False] [--max-concurrent 5] [--cookies browser] [--proxy URL]
| Option | Values | Default |
|---|---|---|
--codec |
Audio: mp3, aac, flac, m4a, opus, vorbis, wavVideo: mp4, mkv, webm, mov, avi, flv |
m4a (macOS) / opus |
--kbps |
64–320 (audio only) | 256 |
--quiet |
True/False (flag) | False |
--max-concurrent |
1–∞ | 5 |
--cookies |
chrome, firefox, edge, etc. | — |
--proxy |
http://, socks5:// | — |
Supported Proxies
fm-dlp supports the following proxy protocols:
| Protocol | Download | Search (yt-video) | Search (yt-music) |
|---|---|---|---|
http:// |
✅ | ✅ | ✅ |
https:// |
✅ | ✅ | ✅ |
socks4:// |
✅ | ✅ | ❌ |
socks5:// |
✅ | ✅ | ❌ |
socks5h:// |
✅ | ✅ | ❌ |
Note:
socks5h://performs DNS resolution through the proxy (remote DNS), whilesocks5://resolves DNS locally. Usesocks5h://for better privacy with Tor.
Examples:
# HTTP proxy
fm-dlp download "URL" --proxy http://user:pass@proxy.example.com:8080
# SOCKS5 (Tor)
fm-dlp download "URL" --proxy socks5://127.0.0.1:9050
# SOCKS5h with remote DNS (recommended for Tor)
fm-dlp download "URL" --proxy socks5h://127.0.0.1:9050
# SOCKS5 for video search
fm-dlp search "query" --platform yt-video --proxy socks5://127.0.0.1:9050
Video container audio codec mapping:
| Video Container | Audio Codec | Typical Use |
|---|---|---|
mp4 |
m4a (AAC) |
Universal compatibility |
mkv |
opus |
High quality, modern |
webm |
opus |
Web, streaming |
mov |
m4a (AAC) |
Apple ecosystem |
avi |
mp3 |
Legacy hardware |
flv |
aac |
Legacy web |
config — Set or view download path
fm-dlp config <path> # Set directory
fm-dlp config # View current setting
Configuration is stored in the standard application config directory:
- Linux:
~/.config/fm-dlp/config.json - macOS:
~/Library/Application Support/fm-dlp/config.json - Windows:
%APPDATA%\fm-dlp\config.json
update — Update the tool
fm-dlp update # Pull latest version via Git
Requires Git to be installed and the project to be a clone of the repository. Not available when installed via pip — use pip install --upgrade fm-dlp instead.
📁 Project Structure
fm-dlp/
├── modules/
│ ├── __init__.py # Package initializer
│ ├── cli.py # CLI entry point (cyclopts App)
│ ├── commands/
│ │ ├── __init__.py
│ │ ├── search.py # YouTube & YT Music search (tracks & albums)
│ │ └── download.py # Async audio/video download engine (yt-dlp)
│ └── utils/
│ ├── __init__.py
│ ├── configer.py # JSON config manager (read/write)
│ ├── validator.py # Input validation (URLs, codecs, proxies, bitrate)
│ │ # + system dependency checks (ffmpeg, git)
│ ├── update.py # Self-update via Git (fetch + hard reset)
│ └── colors.py # Terminal ANSI color constants
├── pyproject.toml # Project metadata & dependencies
├── README.md # Project documentation
└── LICENSE # MIT License
Config file location:
config.jsonis automatically created in your system's standard application config directory on first run. See theconfigcommand section for OS-specific paths.
🔧 Requirements
| Dependency | Purpose |
|---|---|
yt-dlp |
YouTube extraction & download |
mutagen |
Audio metadata tagging |
ytmusicapi |
YouTube Music API |
cyclopts |
CLI framework |
platformdirs |
Cross-platform config paths |
| FFmpeg | Audio/video conversion (system) |
| Git | Self-update mechanism (system, optional) |
📖 Examples
Search Examples
# Search for tracks on YouTube Music
fm-dlp search "Sewerslvt" --limit 10 --platform yt-music
# Search for albums on YouTube Music
fm-dlp search "usedcvnt" --platform yt-music --type album
# Search for videos on YouTube
fm-dlp search "breakcore mix" --platform yt-video --limit 5
# Search with proxy
fm-dlp search "tokyona" --proxy socks5://127.0.0.1:9050
Download Examples
Audio:
# Basic audio download
fm-dlp download "https://youtu.be/..." --codec flac
# Multiple URLs with custom quality
fm-dlp download "URL1 URL2 URL3" --codec mp3 --kbps 320
# Lossless download
fm-dlp download "URL" --codec wav
Video:
# Download as MP4
fm-dlp download "https://youtu.be/..." --codec mp4
# Download as MKV with Opus audio
fm-dlp download "https://youtu.be/..." --codec mkv
# Download as MOV for Apple devices
fm-dlp download "https://youtu.be/..." --codec mov
Advanced:
# Age-restricted content with cookies
fm-dlp download "URL" --cookies firefox
# Anonymous download via Tor
fm-dlp download "URL" --proxy socks5://127.0.0.1:9050
# Quiet mode with increased parallelism
fm-dlp download "URL1 URL2 URL3 URL4 URL5" --quiet --max-concurrent 10
Maintenance
# Update to latest version (pip installation)
pip install --upgrade fm-dlp
# Update to latest version (git clone)
fm-dlp update
Complete Workflow
# 1. Set download location
fm-dlp config ~/Music
# 2. Search for an album
fm-dlp search "we had good times together, don't forget that" --limit 1 --type album
# 3. Download audio from album
fm-dlp download "https://music.youtube.com/playlist?list=OLAK5uy_muvgxae_oLSvDyo0q_zp0JrkBS73nkLMM" --codec flac
# 4. Search and download a video
fm-dlp search "goreshit" --platform yt-video
fm-dlp download "https://youtu.be/gnubBJ6dP4g" --codec mkv
❓ FAQ
Why does fm-dlp exist when yt-dlp already downloads audio and video?
Think of fm-dlp as a purpose-built stereo system, while yt-dlp is a universal multimedia Swiss Army knife. Yes, yt-dlp can extract audio, embed metadata, and download video, but it takes a long string of flags to get there:
# Audio with yt-dlp
yt-dlp -f bestaudio --extract-audio --audio-format mp3 --audio-quality 320k \
--embed-metadata --embed-thumbnail -o "~/Music/%(title)s.%(ext)s" "URL"
# Video with yt-dlp
yt-dlp -f "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best" --merge-output-format mp4 \
-o "~/Videos/%(title)s.%(ext)s" "URL"
fm-dlp wraps all that into a clean, music-focused workflow:
- Search with human-readable, formatted output — no scraping IDs from text dumps
- Download audio or video with a single option — no memorising flag combinations
- Cleaner tags — when used with
searchresults, artist and title come from structured music metadata rather than raw video descriptions with channel suffixes - Automatic format selection — video containers automatically pick the best compatible audio codec
Why does macOS default to M4A while other platforms default to Opus?
The defaults are chosen to match the native music player experience on each operating system:
| Platform | Default | Reasoning |
|---|---|---|
| macOS / iOS | m4a (AAC) |
Apple's entire ecosystem — Finder, Music.app, QuickTime, GarageBand — treats M4A/AAC as the first-class audio format. Album artwork, tagging, and playback are seamless. |
| Linux / Windows | opus |
Opus offers superior perceptual quality at equivalent bitrates. It's the codec modern Android devices, desktop players (VLC, foobar2000, audacious), and browsers use natively. |
You can always override the default with --codec mp3 (universal, legacy
hardware), --codec flac (lossless archival), or any other supported format.
What video formats are supported and how do they work?
fm-dlp supports six video containers: mp4, mkv, webm, mov, avi, and flv.
When you choose a video format, fm-dlp automatically:
- Downloads the best available video stream
- Selects the optimal audio codec for that container (see mapping table above)
- Merges them together using FFmpeg
For example, --codec mkv downloads VP9 video + Opus audio and packs them into an MKV container,
while --codec mp4 prefers H.264 video + AAC audio for maximum device compatibility.
Why is metadata embedding only available for audio?
Metadata embedding (title, artist, album, thumbnail) works only with audio codecs
(mp3, aac, flac, m4a, opus, vorbis, wav) using the mutagen library.
Video containers don't get automatic metadata tagging — this keeps the download
fast and avoids potential issues with video metadata standards.
How does the update command work?
When installed via pip, use pip install --upgrade fm-dlp to update.
When installed from a Git clone, fm-dlp update runs git pull inside the project directory. This means:
- You must have Git installed and accessible from the terminal
- The project must be a Git clone (not a downloaded ZIP)
- It pulls the latest commits from the remote repository
- No version checking or rollback — it's intentionally simple and transparent
Why write this in Python instead of something faster?
The initial version was a personal script that solved a daily annoyance: finding and tagging high-quality music without fighting CLI flags. Python allowed rapid iteration and immediate real-world use.
Most of the actual "work" is performed by highly optimised native code:
yt-dlp for networking, ffmpeg (C/ASM) for transcoding. The Python layer
orchestrates these tools and handles metadata logic in milliseconds — the
network download and ffmpeg encoding dominate execution time regardless of the
language.
Does this break YouTube's Terms of Service?
fm-dlp is an educational tool that demonstrates how public APIs and open-source software can be combined. You are responsible for ensuring your usage complies with the platform's Terms of Service and your local copyright laws. Please support artists you enjoy.
🐛 Troubleshooting
Configuration
| Issue | Solution |
|---|---|
| Config file not found | Run fm-dlp config /your/download/path first |
| "Invalid path" error | Ensure the directory exists and is writable |
| Config reset after update | config.json is preserved across updates — no action needed |
Dependencies
| Issue | Solution |
|---|---|
| "FFmpeg is not installed" | Install FFmpeg and verify: ffmpeg -version• macOS: brew install ffmpeg• Linux: sudo apt install ffmpeg• Windows: winget install ffmpeg |
| "Git is not installed" | Required only for update command: git --version |
Search Issues
| Issue | Solution |
|---|---|
| Album search returns no results | Try different --platform (yt-video vs yt-music) or --type (album vs track) |
| Too few results | Increase limit: --limit 20 |
| Wrong content type | Music search defaults to track. Use --type album for albums |
Download Issues
| Issue | Solution |
|---|---|
| Age-restricted video | Use browser cookies: --cookies chrome (or firefox, edge, brave) |
| Network blocked / 403 error | Use a proxy: --proxy socks5://127.0.0.1:9050 |
| Slow downloads | Increase concurrent downloads: --max-concurrent 10 |
| Audio codec error in video | Video containers auto-select compatible audio. Use mp4 or mkv for best compatibility |
| Video format not supported | Supported containers: mp4, mkv, webm, mov, avi, flv |
| WAV has no metadata | WAV doesn't support embedded tags. Use flac or m4a instead |
| Codec not available | yt-dlp selects best available. Try opus (best quality) or mp3 (compatibility) |
Update Issues
| Issue | Solution |
|---|---|
| "Not a git repository" | update only works if installed via git clone. Use pip install --upgrade fm-dlp for pip installations |
| Update fails | Check internet connection. Force update: git -C /path/to/fm-dlp fetch origin && git -C /path/to/fm-dlp reset --hard origin/main |
Proxy
| Issue | Solution |
|---|---|
| "Invalid proxy URL" | Format: protocol://host:port• HTTP: http://127.0.0.1:8080• SOCKS5: socks5://127.0.0.1:9050 |
| Proxy not working with yt-music | yt-music only supports http:// and https:// proxies |
Still stuck?
Run with verbose output to see detailed errors:
fm-dlp download "URL" --no-quiet
Check yt-dlp version compatibility:
yt-dlp --version
📄 License
MIT License — see LICENSE file.
🙏 Acknowledgments
- yt-dlp — YouTube extraction & download engine
- ytmusicapi — YouTube Music API wrapper
- mutagen — Audio metadata tagging
- cyclopts — Modern CLI framework
- platformdirs — Cross-platform config directory detection
⚠️ Disclaimer
For educational purposes only. Users are responsible for complying with platform Terms of Service and applicable copyright laws.
Author: Fkernel653 Repository: github.com/Fkernel653/fm-dlp PyPI: pypi.org/project/fm-dlp
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fm_dlp-3.0.1.tar.gz.
File metadata
- Download URL: fm_dlp-3.0.1.tar.gz
- Upload date:
- Size: 16.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5b52217b24e7e339c115fc9e0d4027b0eca9c3f4911909b84e518193abcb9114
|
|
| MD5 |
118f47287553e9d4d987052b7bf85eff
|
|
| BLAKE2b-256 |
a35ad0c2bad32af490c6c0c68cf78a3d4b5cc8dd0a1ebcfe34fd2b1f936e25fe
|
File details
Details for the file fm_dlp-3.0.1-py3-none-any.whl.
File metadata
- Download URL: fm_dlp-3.0.1-py3-none-any.whl
- Upload date:
- Size: 18.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8227b73afdeceb9151306640cf8c5ac6696d1b5f2f38984c8dea3515748bdda4
|
|
| MD5 |
70bf05bd93a173d368bb971c591a95ac
|
|
| BLAKE2b-256 |
9b04d6da1263e15065563f631966c8f639cb99774c64a39124196b5db76d563d
|