Nāda (नाद) is Sanskrit for "sound": in Indian music theory, the
primordial sound every note comes from.
nāda is a music player for people who live on the keyboard. Songs on your
disk and music from YouTube share one queue. Play a song and, like YouTube,
nāda lines up what comes next; reorder or remove anything with vim keys.
Lyrics scroll along with the song. If you like a YouTube song, D saves it
to your music folder, with its tags, cover and lyrics, while it keeps
playing. It runs on MPD, so your library, queue
and playback carry on with the window closed.
Contents
Features
- Search everything from one key.
/ opens a floating search over
whatever you're on: your library answers as you type, YouTube a moment
later, with the best match on top; Tab picks where to look (YouTube,
library, playlists, commands, the list you're on). Play, play next, add
or download without leaving the box.
- Now is the lyrics. The window opens on the playing song's lyrics,
large, the current line lit and centred, scrolling with the song. Click a
line to jump there. On the right: the cover, the song's real name and
artists (from YouTube Music, not the upload's title), the album, views,
and what's next.
- Lyrics that show up. Looked up in YouTube Music first (by the video
itself: synced lyrics licensed from LyricFind), then LRCLIB and NetEase;
a
.lrc next to the file or lyrics in its tags come first. A source
that can't be reached is asked again in 30 s, never remembered as "no
lyrics". Hindi lyrics show in Latin letters (Hinglish) or Devanagari.
L opens the lyrics panel: every version the sources have, which one
fits the song's length, [ ] to fix the timing, s for the script.
- Up next, like YouTube. Playing a YouTube song lines up YouTube's own
mix for it; a song from your library brings the rest of its album and
more by that artist. The queue shows what you added and what autoplay
added separately, refills itself as it runs low, and
M turns it off.
- Your queue, edited like text.
dd removes, J/K move a song,
yy/p copy and paste, V selects several, u undoes, Ctrl+r
redoes, and you can drag rows by their handle or click × to remove one.
- Seek anywhere.
, and . skip 10 seconds (3. skips 30), the ⟲ ⟳
buttons do the same, and the progress bar is clickable.
- YouTube without an account. Search it from
/; every result shows
its views and age, and "All YouTube results" opens the full list. Stream links expire after a few hours, so nāda remembers
the video, not the link, and renews it before it plays.
- Download what you like.
D saves a YouTube song as Opus (what
YouTube streams, so nothing is re-encoded) into
~/Music/YouTube/<Artist>/<Title>.opus, with tags, cover art and a
.lrc lyrics file. When it finishes, the queue entry is swapped for the
file in place, and playback carries on from the same second.
Install
Requirements
- Python 3.11+, PyGObject, GTK 4
- MPD (the engine: it plays, keeps the queue and indexes your music)
- yt-dlp for YouTube, and ffmpeg for downloads
- python-ytmusicapi for lyrics from YouTube Music and songs' real names (without it, LRCLIB and NetEase only)
- optional: gtk4-layer-shell (the mini player floats in a corner), mutagen (tags on downloads), a Nerd Font for the icons
# Arch
sudo pacman -S --needed python-gobject gtk4 mpd yt-dlp ffmpeg python-ytmusicapi python-mutagen gtk4-layer-shell ttf-jetbrains-mono-nerd
systemctl --user enable --now mpd
MPD needs a music_directory and an audio output; the Arch wiki
has a five-line config. nāda finds MPD the way every MPD client does:
MPD_HOST / MPD_PORT, else MPD's socket in $XDG_RUNTIME_DIR/mpd/socket,
else localhost:6600.
nāda
git clone https://github.com/Theyashsawarkar/nada ~/.local/share/nada
ln -s ~/.local/share/nada/bin/nada ~/.local/bin/nada
nada # opens the player (it starts itself the first time)
Update with git -C ~/.local/share/nada pull && nada quit.
Usage
nada open the player, or close it if it's open
nada show | hide | mini the full player, hidden, the mini player
nada tab <name> open on a tab: home queue library youtube playlists downloads
nada add [--next|--play] <YouTube URL | file | search words>
nada ctl toggle|play|pause|stop|next|prev
nada ctl seek +10 | seek -10 | seek 1:30
nada ctl vol +5 | vol -5 | vol 40
nada status [--json] what's playing
nada waybar JSON for a waybar module
nada daemon | quit start / stop the player (MPD keeps playing)
The player is one resident process; nada only sends it a D-Bus message,
so it opens at once. ctl, status and waybar talk to MPD directly and
work even when the player isn't running. Closing the window (q, Esc)
only hides it: the music, autoplay and downloads carry on.
Keys
nāda is vim-driven, with Space as the leader, the same grammar as every
Vayu tool: a key you use all the time is one key (j/k, p play/pause,
H/L tabs, dd, yy); everything else is Space, then a group, then
the thing (Space p s shuffle, Space t l the library). Wait a moment after
Space (or g, d, y) and a strip shows what can come next; Esc
cancels. Space Space opens a palette of every action, ? or Space ?
shows every key of the tab you're on. Counts work like vim: 5j, 3.,
2dd; digits are always counts (tabs are H/L, Space t, Ctrl+0..4).
While typing, Ctrl+j/Ctrl+k move. Confirmations take y only.
Moved in this release (the old key says where, then goes away):
Space play/pause is p; queue paste p/P is gp/gP; s shuffle is
Space p s; r repeat is Space p r (r now refreshes); L lyrics is
Space u l (L is the next tab); i info is Space i; zz is
Space g p; a lone 0-4 is H/L or Space t.
Everywhere
| Key | Action |
|---|
j | Move down a song (counts work: 5j) |
k | Move up a song |
g g | Jump to the top (12gg: to the 12th) |
G | Jump to the bottom (12G: to the 12th) |
Ctrl+d | Scroll half a page down |
Ctrl+u | Scroll half a page up |
H | Switch to the previous tab (wraps around) |
L | Switch to the next tab (wraps around) |
Ctrl+Tab | Switch to the next tab (also from the search box) |
Ctrl+Shift+Tab | Switch to the previous tab (also from the search box) |
Ctrl+0 | Switch to Now at once (Ctrl+1 Queue, 2 Library, 3 Playlists, 4 Downloads) |
p | Toggle play / pause |
Enter | Play the selected song |
. | Seek forward 10 seconds (3. = 30 s) |
, | Seek back 10 seconds |
> | Play the next song |
< | Play the previous song |
= | Raise the volume |
- | Lower the volume |
m | Toggle mute |
M | Toggle autoplay (more like this after your songs) |
V | Select several songs (visual mode) |
u | Restore the last change (undo) |
Ctrl+r | Restore an undone change (redo) |
D | Save the playing YouTube song to your music folder (download) |
r | Refresh: rescan the music folder and reload the lists |
/ |
Queue
| Key | Action |
|---|
d d | Remove the song from the queue (2dd: two; u undoes it) |
x | Remove the song from the queue (like dd; u undoes it) |
d G | Remove every song from here to the end (u undoes it) |
y y | Copy the song (yank; 3yy: three) |
g p | Paste removed or copied songs below |
g P | Paste removed or copied songs above |
J | Move the song down |
K | Move the song up |
A | Move the song to play next |
D | Save the YouTube song to your music folder (download; V: the selection) |
n | Jump to the next match (after a "This list" search) |
N | Jump to the previous match |
Space d d | Remove the song from the queue (u undoes it) |
Library
| Key | Action |
|---|
h | Move to the column on the left |
l | Move to the column on the right |
Tab | Switch between artists, albums, genres and folders |
Enter | Play the artist, album or song (replaces the queue) |
a | Add to the end of the queue |
A | Add to play next |
Space a a | Add to the end of the queue |
Space a n | Add to play next |
YouTube results
| Key | Action |
|---|
Enter | Play the result |
a | Add the result to the end of the queue |
A | Add the result to play next |
D | Save the result to your music folder (download) |
Space a a | Add the result to the end of the queue |
Space a n | Add the result to play next |
Playlists
| Key | Action |
|---|
h | Move to the playlists |
l | Move to the playlist's songs |
Enter | Play the playlist (replaces the queue) |
a | Add the playlist to the end of the queue |
A | Add the playlist to play next |
d d | Delete the playlist (asks first) |
D | Save the playlist's YouTube songs to your music folder (download) |
Space a a | Add the playlist to the end of the queue |
Space a n | Add the playlist to play next |
Space d d | Delete the playlist (asks first) |
Downloads
| Key | Action |
|---|
Enter | Play the saved song |
R | Retry a failed download |
d d | Delete the saved file (asks first) |
Space x r | Retry a failed download |
Space d d | Delete the saved file (asks first) |
Now
| Key | Action |
|---|
Enter | Toggle play / pause |
Queue, visual mode (V)
| Key | Action |
|---|
d | Remove the selected songs (u undoes it) |
x | Remove the selected songs (like d; u undoes it) |
y | Copy the selected songs (yank) |
D | Save the selected YouTube songs (download) |
V | Leave visual mode |
Esc | Leave visual mode |
YouTube results, visual mode (V)
| Key | Action |
|---|
a | Add the selected results to the end of the queue |
A | Add the selected results to play next |
D | Save the selected results (download) |
V | Leave visual mode |
Esc | Leave visual mode |
Lyrics panel (Space l l)
| Key | Action |
|---|
j | Move down through the versions the sources have |
k | Move up through the versions |
Enter | Use these lyrics (kept for the song) |
s | Switch the script: Hinglish (Latin letters) or Devanagari |
[ | Show the lyrics earlier by 0.25 s (kept for the song) |
] | Show the lyrics later by 0.25 s (kept for the song) |
Esc | Close the lyrics panel (q too) |
Search panel (/)
| Key | Action |
|---|
Tab | Switch where to look (all, YouTube, library, playlists, commands, this list) |
Shift+Tab | Switch back where to look |
Ctrl+j | Move down through the results while typing |
Ctrl+k | Move up through the results while typing |
Enter | Play the result (a playlist: replace the queue; a command: run it) |
Ctrl+Enter | Play the result next |
Shift+Enter | Add the result to the end of the queue |
Ctrl+d | Download the result (YouTube) |
Ctrl+u | Clear the search box |
Ctrl+x | Clear recent searches |
Esc | Close the search panel |
Palette (Space Space)
| Key | Action |
|---|
Ctrl+j | Move down through the actions (Down too) |
Ctrl+k | Move up through the actions (Up too) |
Enter | Run the action |
Esc | Close the palette |
While a key waits
| Key | Action |
|---|
Esc | Cancel a pending key or count (Space, g, d…) |
Mini player (z)
| Key | Action |
|---|
Space | Toggle play / pause |
. / , | Seek forward / back 10 seconds |
> / < | Play next / previous song |
z / Enter | Switch back to the full player |
q / Esc | Close the mini player (the music keeps playing) |
Commands
Typed after :, like vim.
| Command | Does |
|---|
:w <name> | Save the queue as a playlist (YouTube songs included) |
:e <name> | Replace the queue with a playlist (:e alone opens Playlists) |
:yt <search> | Play the top YouTube result, and its mix after it |
:play <search> | Play a song from your library (falls back to YouTube) |
:add <url or search> | Add to the end of the queue |
:seek 1:30 · :seek +30 | Jump to a time, or by an amount |
:vol 40 · :vol +10 | Set or change the volume |
:sleep 30m · :sleep off | Fade out and pause after a while |
:lyrics <search> | Pick the lyrics by hand (remembered for the song) |
:autoplay on · off | Same as M |
:dl | Download the playing song |
:clear | Empty the queue (u brings it back) |
:q · :qa | Hide the window · quit the player |
Configuration
Everything is optional, in ~/.config/nada/config.toml:
[nada]
autoplay = true # line up more songs after yours (M toggles it, and it's remembered)
download_dir = "YouTube" # inside MPD's music directory
format = "opus" # opus (no re-encoding) | mp3 | m4a
seek_step = 10 # seconds for , and .
volume_step = 5
notify = true # a notification when the song changes (while the window is hidden)
opacity = 0.62 # window background: 1 is solid, lower shows the blur behind it
# (unset: your varna theme's panel glass, so it matches Vyom's panels)
music_dir = "" # default: MPD's music_directory
~/.config/nada/style.css is loaded last, to restyle anything (the default
look is Catppuccin Mocha with a mauve accent: see nada/style.css). With
varna installed, nāda takes the
current theme's colours instead (varna tool nada <theme> gives it its own)
and restyles as soon as the theme changes.
Desktop integration
sway (the same works with any compositor's key bindings):
exec nada daemon
bindsym $mod+Shift+m exec nada # open / hide
bindsym $mod+Mod1+space exec nada ctl toggle # without opening anything
bindsym $mod+Mod1+period exec nada ctl next
bindsym $mod+Mod1+comma exec nada ctl prev
for_window [app_id="^dev\.vayu\.Nada$"] floating enable, resize set 1180 720, move position center
Media keys going through playerctl work as they are: nāda speaks MPRIS.
On SwayFX, blur enable, corner_radius 20 in that for_window rule gives
the window its glass look; the mini player is a layer-shell surface named
nada (layer_effects "nada" { blur enable; corner_radius 18; }).
waybar, a module that shows what's playing (and disappears when
nothing is):
"custom/nada": {
"exec": "nada waybar",
"return-type": "json",
"on-click": "nada ctl toggle",
"on-click-middle": "nada ctl next",
"on-click-right": "nada",
"on-scroll-up": "nada ctl seek +10",
"on-scroll-down": "nada ctl seek -10"
}
Its class is play, pause or stopped, to style each state.
From other tools: nada add --play <url> plays a YouTube link with its
mix after it; raga, the YouTube
search panel, uses exactly that.
How it works
raga, keys, waybar ──► nada (bin/nada: D-Bus) ──► the player process ──► MPD ──► speakers
│
├─ yt-dlp: search, mixes, stream links, downloads
├─ LRCLIB: lyrics
└─ MPRIS: media keys, phone, playerctl
nada/core.py is the model: MPD's queue and state, plus what MPD doesn't
do (YouTube songs and their expiring links, autoplay, undo, downloads,
lyrics, covers). Slow work runs on worker threads and reports back on
the GTK main loop.
nada/window.py is the window and the vim key engine (modes, counts,
pending operators, registers); nada/views.py the six tabs and the right
pane; nada/mini.py the mini player; nada/mpris.py MPRIS.
- YouTube songs sit in MPD's queue as stream URLs, tagged with their video
id, so other MPD clients see and play them too.
Troubleshooting
- "MPD isn't running".
systemctl --user start mpd (and enable it).
nāda reconnects by itself.
- No sound but it says it's playing. That's MPD's audio output: check
audio_output in your mpd.conf (PipeWire users: type "pipewire" or
"pulse").
- "Volume control unavailable". Your MPD output has no mixer; set
mixer_type "software" in its audio_output block.
- A YouTube song won't play. Update yt-dlp first (
yt-dlp -U, or your
package manager): YouTube changes often and yt-dlp follows.
- Wrong or missing lyrics.
:lyrics <artist> <song> picks them by hand.
- Anything else. The player's log has the details:
journalctl --user -u nada -u nada-daemon -b (without systemd: ~/.local/state/nada/daemon.log);
please open an issue with it.
Contributing
Bug reports, ideas and pull requests are welcome: see
CONTRIBUTING.md for the development setup and the rules
the code follows, and CHANGELOG.md for what changed in each
release. Please report security issues privately (SECURITY.md).
nāda is part of Vayu, a
keyboard-driven Wayland desktop, and works on its own on any desktop with
MPD.
License
MIT