Skip to main content

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

Python PyPI License Platform Ruff

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
  • Cross-platform Config — Stores config in standard app config directory (XDG, AppData, Application Support)

🚀 Quick Start

Prerequisites

  • Python 3.10+ & FFmpeg

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-dlp with python modules/cli.py in 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, wav
Video: 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), while socks5:// resolves DNS locally. Use socks5h:// 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

📁 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)
│       └── colors.py        # Terminal ANSI color constants
├── pyproject.toml           # Project metadata & dependencies
├── README.md                # Project documentation
└── LICENSE                  # MIT License

Config file location: config.json is automatically created in your system's standard application config directory on first run. See the config command 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)

📖 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 install --upgrade fm-dlp

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 search results, 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:

  1. Downloads the best available video stream
  2. Selects the optimal audio codec for that container (see mapping table above)
  3. 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.

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

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)

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fm_dlp-3.1.1.tar.gz (15.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fm_dlp-3.1.1-py3-none-any.whl (17.6 kB view details)

Uploaded Python 3

File details

Details for the file fm_dlp-3.1.1.tar.gz.

File metadata

  • Download URL: fm_dlp-3.1.1.tar.gz
  • Upload date:
  • Size: 15.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for fm_dlp-3.1.1.tar.gz
Algorithm Hash digest
SHA256 5be9835f6887169650bb9360a3df529aa8d04fb4cd1671f3838b87ce64b1ddd1
MD5 9a8fa864ccdf48a96eb99847ddb0155e
BLAKE2b-256 13781f6671ae7c9aee4eb05260c94a1d059b241a78ee48c7a14ea3d74bbfaea1

See more details on using hashes here.

File details

Details for the file fm_dlp-3.1.1-py3-none-any.whl.

File metadata

  • Download URL: fm_dlp-3.1.1-py3-none-any.whl
  • Upload date:
  • Size: 17.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for fm_dlp-3.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 efbc8b1203645a7714bb5f8cb6cd6cbf30ed19a76d90f8b5806de85e11356c49
MD5 618d9adce2a4add63bd14ab5757f373c
BLAKE2b-256 91900a966f85bc8c9a91ed6a59c165afe0bda3585198be156e7d91e03059e8be

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page