v0.2 - Playlist support is here!
- Press
fto access playlists menu - Create, delete, and manage your playlists
- Add songs from search results with
a - Auto-play: when a song ends, the next one starts automatically
- Everything saved in
~/.shellbeats/so your playlists persist between sessions - All UI now in English (finally cleaned up those Italian strings)
- 100% translated in english no more half italian words.
A terminal music player for Linux. Search YouTube and stream audio directly from your command line.
I wrote this because I use a tiling window manager and I got tired of:
- Managing clunky music player windows that break my workflow
- Keeping browser tabs open with YouTube eating up RAM
- Getting distracted by video recommendations when I just want to listen to music
shellbeats stays in the terminal where it belongs. Search, play, done.
┌────────────────────────────────────────────────────────────────────────────┐
│ SHELLBEATS │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ TUI │ │ yt-dlp │ │ mpv │ │ Audio │ │
│ │Interface │ ───> │ (search) │ │ (player) │ ───> │ Output │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │ │ ▲ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌──────────┐ │ │
│ └─────────> │ IPC │ ────────────┘ │
│ │ Socket │ │
│ └──────────┘ │
└────────────────────────────────────────────────────────────────────────────┘
- You search for something
- yt-dlp fetches results from YouTube
- mpv streams the audio (nothing saved to disk)
- IPC socket handles communication between shellbeats and mpv
The auto-play feature uses mpv's IPC socket to detect when a track ends. Here's the deal:
- shellbeats connects to mpv via a Unix socket (
/tmp/shellbeats_mpv.sock) - The main loop uses
poll()to check for events without burning CPU cycles - When mpv finishes a track, it sends an
end-fileevent withreason: eof - shellbeats catches this and automatically loads the next song
There's a small catch though: when you start a new song, mpv might fire some events during the initial buffering phase. To avoid false positives (like skipping through the whole playlist instantly), there's a 3-second grace period after starting playback where end-file events are ignored. The socket buffer gets drained during this time so stale events don't pile up.
It's not the most elegant solution, but it works reliably without hammering the CPU with constant status polling.
Playlists are stored as simple JSON files:
~/.shellbeats/
├── playlists.json # index of all playlists
└── playlists/
├── chill_vibes.json # individual playlist
├── workout.json
└── ...
Each playlist file just contains the song title and YouTube video ID. When you play a song, shellbeats reconstructs the URL from the ID. Simple and easy to edit by hand if you ever need to.
mpv- audio playbackyt-dlp- YouTube search and streamingncurses- terminal UI
Install dependencies:
# Debian/Ubuntu
sudo apt install mpv libncurses-dev yt-dlp
# Arch
sudo pacman -S mpv ncurses yt-dlpBuild:
make
make installbinary file will be copied in /usr/local/bin/
Run:
shellbeats| Key | Action |
|---|---|
/ or s |
Search YouTube |
Enter |
Play selected song |
Space |
Pause/Resume |
n |
Next track |
p |
Previous track |
x |
Stop playback |
q |
Quit |
| Key | Action |
|---|---|
↑/↓ or j/k |
Move selection |
PgUp/PgDn |
Page up/down |
g/G |
Jump to start/end |
Esc |
Go back |
| Key | Action |
|---|---|
f |
Open playlists menu |
a |
Add current song to a playlist |
c |
Create new playlist |
d |
Remove song from playlist |
x |
Delete playlist (when in playlists view) |
-
Investigate rare playback issue: Some searched songs don't start playing for some reason. Not sure yet if it's a yt-dlp thing, an mpv thing, or something in my code. Need to dig into the logs and figure out what's happening. If you hit this, try searching for the same song again or pick a different result.
-
Volume controls
-
Shuffle mode for playlists
-
Maybe some kind of queue system separate from playlists
MIT - do whatever you want with it.

