Rust + yt-dlp + ratatui

A terminal
music player

Stream audio from YouTube, Bilibili, SoundCloud, and hundreds more sites — directly in your terminal. No local files, no disk writes. Powered by yt-dlp and Rust.

▸ Install View on GitHub
music-player — 80×24
┌ Playlist ────────────────────────────────────────────────────────────────────────────┐ │ 1. Lofi Beats │ │ 2. Jazz Vibes │ │ 3. Rain Sounds │ │ 4. Night Drive │ │ ▶ 5. City Lights└──────────────────────────────────────────────────────────────────────────────────────┘ ┌ Status ──────────────────────────────┐┌ Progress ────────────────────────────┐┌ Mode ┐ │Now playing: City Lights ││█ 03:45 / 48:30 ││ ↺ │ └──────────────────────────────────────┘└──────────────────────────────────────┘└──────┘ [a] Add [Enter] Play [Space] Pause [r] Reset [d] Delete [m] Mode [1-n] Goto

Why build this?

In the age of AI coding, the command line is your battlefield. This is an immersive TUI music player that lets you stay right inside the Terminal — switch tracks and keep the music going with nothing but your keyboard, so your flow never breaks.​

In-Memory Streaming

yt-dlp pipes audio directly into a shared buffer; rodio decodes and plays progressively. Playback starts before the download finishes.

🌐

Site-Agnostic

Works with any URL yt-dlp supports — YouTube, Bilibili, SoundCloud, NicoNico, and hundreds more.

📋

Playlist Management

Add, delete, rename, and reorder songs. Persisted as JSON in your platform's config directory. Survives restarts.

Quick Jump

Press a number key (1–9), then Enter to jump directly to a song. Rapid inputs are coalesced — only the last request plays.

🔁

Playback Modes

Cycle between Sequential, Repeat One, and Shuffle with a single key press.

💾

Position Memory

Automatically resumes from where you left off. Press r to restart from the beginning.

Seek & Progress

/ to jump ±10 seconds. Real-time progress bar shows current and total time.

🖥️

Cross-Platform

Linux, macOS, Windows. All it needs is Rust 1.85+ and yt-dlp installed on your system.

Screenshots

A clean TUI designed for efficiency — five screens for a fluid music experience.

Playlist View
Playlist — Browse and play songs from your playlist
Add Song View
Add Song — Paste a URL and set an alias to add a new song
Edit Alias View
Edit Alias — Rename any song in your playlist
Split View - Claude Code
Split View (Claude Code) — AI-assisted development session
Split View - Hermes Agent
Split View (Hermes Agent) — Multi-agent collaborative coding

Get Started

Build from source or install directly from crates.io. Requires Rust 1.85+ and yt-dlp.

▸ cargo Install from crates.io
cargo install terminal-music-player
▸ bash Build from source
# Clone the repository
git clone https://github.com/dennislan/terminal-music-player.git
cd terminal-music-player

# Build in release mode
cargo build --release

# The binary is at target/release/music-player
./target/release/music-player
▸ bash Install yt-dlp
# macOS
brew install yt-dlp

# Linux (Debian/Ubuntu)
sudo apt install yt-dlp

# Windows (scoop)
scoop install yt-dlp

Keyboard Shortcuts

Entirely keyboard-driven. No mouse needed.

Key Action
↑ / ↓ or k / j Navigate playlist
Enter Play selected song
0–9 then Enter Jump to song by number (1-based)
Space Pause / Resume
← / → Seek −10s / +10s
r Reset current song to 00:00
m Cycle playback mode (Sequential → Repeat One → Shuffle)
a Add a URL
e Edit selected song's alias
d Delete selected song (with confirmation prompt)
Alt+↑ / Alt+↓ Move song up / down in the playlist
q Quit (saves position and playlist)
Esc Cancel number input / dismiss dialog

Architecture

The player runs in a dedicated background thread, communicating with the TUI via mpsc channels.

▸ tree Module structure
src/
├── main.rs        Entry point, terminal setup, event loop, key dispatch
├── lib.rs         Library crate root (exposes modules for integration tests)
├── app.rs         Application state (App), screen management, input handling
├── ui.rs          ratatui rendering — five screens
├── stream.rs       yt-dlp subprocess, streaming buffer
├── player.rs       Background thread, mpsc channels, rodio playback
└── playlist.rs     Song & Playlist structs, JSON persistence

Player Thread Communication

TUI Event Loop
Commands (mpsc) → ← Events (mpsc)
Player (thread)
rodio (audio)

Commands (UI → Player)

Play(Song)
Stop
PauseResume
SeekTo(f64)

Events (Player → UI)

Buffering
Started
Position
Paused / Resumed
Finished / Stopped / Error

Audio Streaming Flow

yt-dlp stdout
StreamHandle
Arc<Mutex<Vec<u8>>> + Condvar
rodio::Decoder
DeviceSink

Sponsors

Heartfelt thanks to every sponsor — your generosity drives this project forward.

☕ Buy Me a Coffee

If you find this project helpful, your support keeps the late-night coding fueled.

WeChat Pay
AliPay
WeChat Pay AliPay