mpv-music is a blazing-fast, terminal-native music player and library browser. Originally a Bash hybrid, it has been completely rewritten in Rust for maximum performance, safety, and a seamless TUI experience.
It indexes your music collection into a lightning-fast library, providing fuzzy searching (via skim), metadata-rich previews, and deep integration with mpv for high-quality playback.
Note
This is the documentation for the Rust-native rewrite (v0.24+). mpv-music has migrated from the legacy Bash hybrid system to a unified Rust core.
If you are looking for the archived Bash-based version, see: mpv-music-sh-archive
- Key changes in Rust Rewrite
- Features
- Dependencies
- Installation
- Usage
- Indexing
- Configuration
- FAQ
- Development
- License
- GenAI Disclosure
- Single Binary: No more managing a Bash script + a separate indexer binary. Everything is now one efficient executable.
- Native TUI: Replaced external fzf calls with an integrated Rust TUI based on skim, allowing for deeper UI customization and better performance.
- Static Linking: Linux releases are now built with musl, making them "portable"—they run on almost any distribution without worrying about GLIBC versions.
- Faster Scans: The indexing engine is now part of the main app, leveraging Rust's multi-threading to scan thousands of files in milliseconds.
- Leaner Dependencies: Significantly reduced the number of external tools required to run.
- Lightning-Fast Indexing: Automatically scans your music directories and caches metadata (Artist, Album, Title, Genre) into a JSONL index.
- Advanced Fuzzy Search: Instant, interactive searching through your entire library.
- Self-Healing Index: Automatically validates index integrity on startup. It detects corruption (e.g., from power loss), surgically repairs broken lines to save your library, or triggers a smart rebuild to prevent crashes. In a blink of an eye.
- Rich Metadata Previews: View song title, artist, album, and genre directly in the skim preview window.
- Interactive Selection with Multiple Modes:
- Directory Mode: Navigate folders with clean names instead of full paths.
- Track Mode: Fuzzy-search individual tracks with metadata previews.
- Playlist Mode: Find and play your saved
.m3uor.plsplaylists. - Tag Filter Mode: Drill down by genre, artist, album, or title interactively.
- Play All: Instantly play your entire indexed library.
- Search & Stream URL: Search YouTube or stream URLs directly from the menu.
- Settings: Manage mpv-music settings directly from the menu.
- Direct File/URL Playback: Instantly play local audio/video files or URLs (YouTube, streams) without going through the menu.
- Custom Directory Support: Pass a folder path to browse and filter only that directory instead of your full library.
- CLI Filtering: Use flags like
--genre,--artist,--album,--titlefor direct filtering. Pass a value or omit it to open an interactive picker. - Smart Matching: CLI filters attempt exact matches first, then fall back to partial matches with disambiguation.
- Configurable File Types: Support for both audio and video extensions, easily tweakable.
- Custom MPV Flags: Pass mpv flags directly or set defaults in the config.
- Video Toggle:
--video-oklets you include videos in your library scans. - Visual Playback:
--watch (-w)forces the MPV window to open, allowing you to watch videos or see cover art/visualizations during playback. - YouTube Auto-Config: Automatically detects JS runtimes (Deno, Node, QuickJS, Bun) for yt-dlp YouTube playback.
- Enhanced Logging: Verbose/debug modes with log rotation and configurable log file size.
- mpv - https://mpv.io
- yt-dlp - for playing URLs. https://github.com/yt-dlp/yt-dlp
- JS Runtime - for YouTube playback (Deno, Node.js, QuickJS, or Bun). Deno is recommended.
Note
YouTube playback now requires a JS runtime to bypass anti-bot protections.
mpv-music automatically detects and configures Deno, Node, QuickJS, or Bun for yt-dlp.
If you installed yt-dlp via a package manager (apt/dnf/pacman) instead of the official GitHub binary, it might be missing components. Try enabling the remote fix in your config (mpv-music --config):
ytdlp_ejs_remote_github = true
- Linux: Native. The script is built and tested primarily for Linux (GNU tools).
- WSL (Windows Subsystem for Linux): Fully Supported. This is the recommended way to run it on Windows.
- macOS / BSD: It should work fine on macOS and BSD systems (haven't tested it, please do... any feedback is appreciated).
- Windows (Native/Git Bash): Not Supported. Check FAQ.
Tip
You can use WSL (Windows Subsystem for Linux) to run mpv-music on Windows.
If you have Rust installed:
# Full installation with update checker
cargo install mpv-music --features update
# Minimal installation (smaller binary, no --update flag)
cargo install mpv-music- Download the latest binary for your architecture from the Releases page.
- Make it executable and move it to your path:
chmod +x mpv-music mv mpv-music ~/.local/bin/
or Alternatively, you can use the following command and let the script handle the process
curl -sL https://raw.githubusercontent.com/FurqanHun/mpv-music/master/install.sh | bashRequires Rust 1.93.0+.
git clone https://github.com/FurqanHun/mpv-music.git
cd mpv-music
cargo build --release
# Binary will be at target/release/mpv-musicmpv-musicImportant
Running mpv-music for the first time will automatically index $HOME/Music.
It is recommended that you first run mpv-music --manage-dirs to customize music directories before indexing (unless you only keep your music in $HOME/Music). And if your music is on an HDD, you may want to run --serial or set SERIAL_MODE=true in your config, using mpv-music --config.
That creates:
-
Config:
~/.config/mpv-music/config.toml -
Index:
~/.local/share/mpv-music/music_index.jsonl -
Logs:
~/.local/share/mpv-music/mpv-music.log
The project now respects XDG standards. and only uses config folder to dump all as a fallback. And by directories library used does support config/data dirs in windows/mac.
mpv-music [PATH_OR_URL_OR_DIR] [OPTIONS]
mpv-music [FILTER_FLAGS] [--play-all]- No args: Runs interactive selection on your configured music directories.
- File or URL: Plays it instantly.
- Folder path: Runs interactive search using just that folder.
| Option | Description |
|---|---|
[TARGET] |
Directly play a file, directory, or URL |
-r, --refresh-index |
Update index (incremental scan). Detects new/changed files. |
--reindex |
Force a full re-scan of the library. |
-u, --update |
Check for application updates. |
--add-dir <PATH>... |
Add directory (e.g. --add-dir /music /other). |
--remove-dir <PATH>... |
Remove directory (aliases: --rm-dir). |
--manage-dirs |
Open the Interactive Directory Manager. |
-c, --config [<EDITOR>] |
Edit config file. |
--remove-config |
Delete config file (Reset) (aliases: --rm-conf). |
--log [<PAGER>] |
View logs. |
--remove-log |
Delete log file (aliases: --rm-log). |
-p, --play-all |
Play all tracks immediately. |
-l, --playlist [<VAL>] |
Open Playlist Mode. Opens picker if no value given. |
--video-ok |
Allow video files. |
no-video |
Negates --video-ok, and overrides it in config. |
--watch (-w) |
Play with video window enabled (forces visual mode). |
--no-watch |
Disable video window (forces audio mode, which is the default). |
--loop [<LOOP_ARG>] |
Enable looping (inf, no, track, or a NUMBER). |
--no-loop |
Disable all looping. |
--repeat |
Loop the current track (Repeat One). |
-e, --ext <EXT_LIST> |
Override allowed extensions (e.g. -e mp3,flac). |
-g, --genre [<GENRE>] |
Filter by Genre (e.g. -g 'Pop,Rock'). |
-a, --artist [<ARTIST>] |
Filter by Artist (e.g. -a 'ado,gentle'). |
-b, --album [<ALBUM>] |
Filter by Album. |
-t, --title [<TITLE>] |
Filter by Title (Partial). Opens Track Mode if no value given. |
-v, --verbose |
Display Verbose Information. |
-d, --debug |
Debug mode. |
--volume <VOLUME> |
Set volume (0-100). |
-s, --shuffle |
Shuffle. |
--no-shuffle |
No Shuffle. |
--serial |
Force serial (single-threaded) processing. |
--search [<SEARCH>] |
Search YouTube directly (aliases: --yt). |
-h, --help |
Print help. |
-V, --version |
Print version. |
Any mpv flag also works: --no-video, --volume=50, --shuffle, etc.
Instead of using the log rotation method now log is overwritten each time the program is run. And you can turn the logging off by setting enable_file_logging = false in your config.
mpv-music # full interactive menu
mpv-music /path/to/music # interactive in a specific folder
mpv-music ~/Music/track.flac # plays file instantly
mpv-music "https://youtube.com/watch..." # plays URL instantly
mpv-music /path/to/folder -a # pick artist from that folder only
mpv-music --genre="Rock" --play-all # play all rock tracks
mpv-music --artist="Ado" # fuzzy search by artist
mpv-music -p -a ado # play all tracks by Ado
mpv-music -g -a "Daft Punk" -p # pick genre, then play all Daft Punk
mpv-music --volume=50 --shuffle # custom mpv flags
mpv-music --reindex # rebuild the index from scratch
mpv-music --debug # run with full logging enabled
mpv-music --verbose # prints verbose messages
mpv-music --add-dir /path/to/music /path/to/music2 # Add multiple directories
mpv-music --remove-dir /path/to/music /path/to/music2 # Remove multiple directories
mpv-music --manage-dirs # Manage directoriesYour music library is indexed to:
- Where ever our system has defined program data should go, for modern linux systems it should be at
~/.local/share/mpv-music/music_index.jsonl
Searching the filesystem with find every time is slow, especially if you have a large music collection. So mpv-music caches an index using JSONL (JSON Lines) for:
- Fast filtering
- Instant append updates
- Metadata previews
- Offline-friendly behavior
--reindex- Full rebuild--refresh-indexor-r- Smart update (only processes new/modified files)
Tip
Indexing vs. Watching:
- Use
--video-ok(or setvideo_ok = true) to scan and include video files in your library. - Use
--watch((or setwatch = true)) when playing to actually show the video window.
Example: mpv-music --video-ok --reindex to scan, then mpv-music -w to watch.
If a config file does not exist, mpv-music will create one at startup. To customize the behavior:
mpv-music --config
Options:
# --- General Playback ---
shuffle = true
loop_mode = "inf" # Options: "playlist" (same as inf), "track", "no", "inf", "5" (number of loops)
volume = 100
# --- Library Management ---
music_dirs = [
"/home/user/Music",
"/mnt/storage/songs",
]
video_ok = false # Set to true to include video files in the index
watch = false # Set to true to actually show the video window when playing
serial_mode = false # Set to true to force single-threaded scanning (better for HDDs)
# --- YT-DLP / Networking ---
# Set to true if you installed yt-dlp via package manager (apt/pacman).
# Keep false if you downloaded the binary directly from GitHub.
ytdlp_ejs_remote_github = false
ytdlp_useragent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/114.0"
# --- Logging ---
# If true, INFO/WARN logs are saved to file.
# If false, logs are only shown on screen when running with --verbose or --debug.
enable_file_logging = true
# --- File Extensions ---
audio_exts = [
"mp3",
"flac",
"wav",
"m4a",
"aac",
"ogg",
"opus",
"wma",
"alac",
"aiff",
"amr",
]
video_exts = [
"mp4",
"mkv",
"webm",
"avi",
"mov",
"flv",
"wmv",
"mpeg",
"mpg",
"3gp",
"ts",
"vob",
"m4v",
]
playlist_exts = [
"m3u",
"m3u8",
"pls",
]
# --- MPV Arguments ---
# These flags are passed directly to the mpv process.
mpv_default_args = [
"--no-video", # Automatically ignored if --watch is used
"--audio-display=no", # Automatically ignored if --watch is used
"--msg-level=cplayer=warn",
"--display-tags=",
"--no-term-osd-bar",
# Custom Now Playing UI
"--term-playing-msg=╔══ MPV-MUSIC ══╗",
"--term-status-msg=▶ ${?metadata/artist:${metadata/artist} - }${?metadata/title:${metadata/title}}${!metadata/title:${media-title}} • ${time-pos} / ${duration} • (${percent-pos}%)",
]
Q. Why rewrite it in Rust? The Bash version worked fine.
The Bash version was a hack that grew too big. Spawning subshells to parse metadata is slow. Managing fzf integration through pipes is fragile (kinda, it's not really a problem, but for the smooth experience it is). And it was a parsing hell ngl.
Q. Why not use a "real" database like SQLite?
Because you don't need it. Your music library is likely under 100,000 tracks. A flat JSONL (JSON Lines) file is:
- Human readable: You can
catorgrepit. - Fast enough: We load and parse 20,000 lines in milliseconds.
- Corruption proof: If one line gets corrupted, you only lose one song, not the whole database. And it is easily detectable—plus with
refresh-index, it's automatically fixed.
Q. Why doesn't it work on Windows?
Blame the TUI library. We use skim (a Rust port of fzf) for the interface. As of v2.0.2, it does not support Windows natively. Once skim adds support, Windows support will happen. Until then, use WSL. They are working on it, or at least Windows support will be prioritized after the rewrite with ratatui (Issue #293). That being said, I did see some development for Windows support in their PRs, and the testing was recently made cross-platform.
Q. YouTube playback isn't working!
That is likely not a bug in mpv-music. YouTube is constantly fighting yt-dlp.
- Update
yt-dlp(yt-dlp -U). - Make sure you have a JS runtime (Node, Deno, Bun) installed. YouTube now requires executing JavaScript to decipher video signatures.
mpv-musictries to auto-detect this, but it can't perform miracles. - If you installed
yt-dlp, from other sources than official binaries then consider enablingytdlp_ejs_remote_github = trueinconfig.toml. - Or you can try changing the
ytdlp_useragentin config.
Q. mpv-music isn't picking up metadata for video files or some other audio formats?
The original mpv-music utilized ffprobe to parse metadata from everything. The Rust version uses lofty (native Rust library) for metadata parsing, which is infinitely faster (in some sense) but supports fewer formats (mostly Audio).
Currently supported formats by lofty:
| File Format | Metadata Format(s) |
|---|---|
| AAC (ADTS) | ID3v2, ID3v1 |
| Ape | APE, ID3v2*, ID3v1 |
| AIFF | ID3v2, Text Chunks |
| FLAC | Vorbis Comments, ID3v2* |
| MP3 | ID3v2, ID3v1, APE |
| MP4 | iTunes-style ilst |
| MPC | APE, ID3v2*, ID3v1* |
| Opus | Vorbis Comments |
| Ogg Vorbis | Vorbis Comments |
| Speex | Vorbis Comments |
| WAV | ID3v2, RIFF INFO |
| WavPack | APE, ID3v1 |
For unsupported formats, the indexer falls back to filename parsing. I may implement an opt-in ffprobe fallback in the future if there is demand, but right now there's me and one other person I know of that actually uses this and we don't need it.
- Source Code: Located in
src/.main.rs: Entry point. Initializes configuration, logging, and dependencies before passing control to the TUI.cli.rs: Defines the command-line interface arguments and flags (usingclap).
tui/: The Terminal User Interface module.mod.rs: Core orchestration, menu loops, and user interaction logic.items.rs: Data structures for list items (Tracks, Directories, Playlists).
config.rs: Manages configuration loading, validation, and defaults (Toml).indexer.rs: The core library scanner. Useswalkdir,rayon(parallelism), andloftyfor metadata.player.rs: Wraps thempvprocess, handling playback control, queue generation, and temporary file cleanup.search.rs: YouTube Backend. Wrapsyt-dlpto fetch search results and stream URLs.dep_check.rs: Validates runtime dependencies (mpv, yt-dlp versions) and environment health.update.rs: Handles version comparison (SemVer) and checks GitHub for releases.
MIT License. See LICENSE.
Generative AI (specifically Google Gemini, and sometimes others) was and is used for maintenance and development as an assistive tool.