Skip to content

Usage

The TUI

Launch with bester-ytm. The layout has three panes: search results on the left, the playlist/queue in the center, and playback, playlist controls, and the playlist builder on the right. The footer shows the shortcuts for the focused pane; ? opens an overlay with every binding.

Keys

Pane-scoped keys act only while their pane has focus: x, Shift+Space, a, A, and Enter-on-results need the results pane; j/k, c, and w need the queue pane; s, d, Space-as-select, and Enter-on-queue work from either list pane. The footer always shows which keys are live.

/          focus search
Enter      play selected search result, playlist, or queue item
x          mark/unmark the highlighted search result
Shift+Space  range-select: mark every song from the first marked one
           through the highlighted row (shift+click does the same)
a          add the highlighted song or album to the queue, or every row
           marked with x (keeps what is already queued)
A          play now, replacing the queue: the highlighted or marked songs
           in song results, or the album/highlighted song in album
           searches (shift+a)
Space      play/pause; in the results pane it marks the highlighted
           song instead (same as x)
n          next track
p or b     previous track
s          shuffle playlist/queue
c          clear the queue (keeps the playing track)
d          remove the highlighted queue track (the playing row is kept;
           press n to skip it); in search results, delete the highlighted
           playlist (local or YouTube) after a confirming second press
j / k      move the highlighted queue track down / up
w          save the queue as a local playlist (also the Save button)
g          add 5 AI-suggested similar tracks to the queue; type digits
           right after g to change the count (g11 adds 11), Esc cancels
i          build a playlist from the builder prompt (right pane)
t          toggle transition style (cut / crossfade)
[ / ]      shorten / lengthen the crossfade (1-15s)
v          cycle the visualizer (Mythos, Oracle, Bars, Wave, Pulse, Scope)
Left/Right seek -10s/+10s
,/.        seek -30s/+30s
- / = / +  volume down / up (both = and + raise it)
m          mute/unmute
f          fav/unfav the highlighted song (or the playing track); faved
           songs show a trailing * and pressing f again removes them;
           logged in, favs also like the song on YouTube Music, and on
           radio f favs the song the station is playing
Ctrl+P     show playlists (local first, then your YouTube library)
Ctrl+A     show auth status
Tab / Shift+Tab  cycle panes forwards / backwards
?          show all key bindings in an overlay (Escape, q, or ? closes it)
q          quit

Search syntax

The search box understands structured queries:

song:metallica                      songs ranked by relevance (songs: also works)
album:metallica                     albums by name (albums: also works)
album:metallica,year:1986           albums from a given year
artist:sepultura                    popular songs by the artist
artist:sepultura,albums             the artist's albums
artist:sepultura,year:1998,songs    tracks from the artist's 1998 releases
playlist:                           your local playlists (playlists: also works)
playlist:indie                      community playlists on YouTube Music
favs:                               your faved songs (favorites: and liked: too)
favs:sepultura                      faved songs matching the text
radio:                              web radio stations (ByteFM, KALX, your own)
local:~/Music                       audio files under a local folder
/home/you/Music/song.mp3            a pasted path also works (/, ~, or ./)

song: lists individual tracks; album: shows a tree of album names in the left pane. Each album title is a branch you expand to its songs:

left pane (album search)
- Enter on an album title    expand/collapse it (songs load on first expand)
- Enter on a song            play it now (or queue it if something is playing)
- Space / x                  mark/unmark the highlighted row (marked *)
                               on an album title this marks all its songs
- Shift+Space                range-select from the first marked song to the
                               highlighted one (shift+click does the same)
- a                          add to the queue (keeps what is already there):
                               album title -> all its songs
                               song        -> that one song
                               any selected -> every selected song, in order
- A (shift+a)                play now, replacing the whole queue:
                               album title -> the whole album from the top
                               song        -> the album from that song on
                               any selected -> the selected songs

a keeps the current queue and appends; A clears it and starts the album immediately. With an empty queue, a (or Enter on a song) also starts playback; with a loaded but stopped queue it only appends. artist:...,albums still lists albums in the normal results pane, where Enter loads the whole album into the queue. Selecting a playlist loads its tracks into the center queue pane. Ctrl+P lists all your playlists in one place: locally saved playlists (marked LOCAL PLAYLIST) first, then your YouTube Music library playlists when logged in.

In song results, mark songs with x or Space (marked rows show a *); Shift+Space or shift+click marks the whole range from the first marked song through the highlighted one. Press a to add every marked song to the queue in list order, or Enter to do the same. While something is playing (or a loaded queue is stopped), the songs are appended without interrupting it; with an empty queue the first one starts and auto-advance plays the rest.

Playback and transitions

The current track is marked NOW. When a track nears its end and the transition style is crossfade (the default, 6 seconds), the next queued track is prebuffered on a second silent mpv deck and blended in DJ-style with an equal-power fade; set the transition to cut for instant switches. The DECK line in the right pane shows the active deck and becomes a MIX meter while two tracks blend. While audio plays, glowing audio-reactive panels run in the bottom of every pane; pick a style with the Visuals dropdown or cycle with v, and choose a theme from the command palette (the circle in the header). Clicking anywhere on the progress bar seeks to that position. On slow or remote terminals, lower ui.visual_fps in the config (or set it to 0) to ease the rendering load.

Favorites

f favs the highlighted song when the queue or results pane has focus, and the playing track otherwise. Faved songs show a trailing * in the queue, in search results, and on the Now Playing label; pressing f on a faved song removes it again. Type favs: in the search box to list your favorites — liked: and favorites: do the same (add text, e.g. favs:sepultura, to filter); the rows behave like any song result, so Enter, a, and f all work there. Favorites live in favorites.json under the app's data directory.

When you are logged in, faving also likes the song on YouTube Music (and unfaving removes the like), so your local favorites and your YTM liked songs stay in step.

Web radio

Type radio: in the search box to list the web radio stations (rows are labelled RADIO): ByteFM and KALX ship built in, and you can add your own in the config (see Configuration). Enter on a station tunes to it: whatever is playing stops with a hard cut (no crossfade), the station starts, and it becomes the queue's only row — selecting another station switches the same way, so there is never more than one station in the queue. While a station plays, the Now Playing label shows the live track (ByteFM · Artist - Song), refreshed every ~20 seconds from the station's metadata, and g finds songs similar to that live track (not to the station) and queues them after it.

Pressing f while radio plays favs the song the station is playing, not the station: the track is looked up on YouTube Music, liked there, and saved to your local favorites. The status line names the match so a wrong hit is easy to spot. This needs a login; radio playback itself does not.

To add a station without hunting for its stream URL yourself, type add radio station <name> (e.g. add radio station WFMU) into the playlist builder box and press Build: the configured AI provider looks up the station's direct stream URL, bester-ytm verifies the URL actually serves audio, and the station is written to [radio.stations] in config.toml — it then shows up under radio:. If the AI cannot find a working stream, the status line says so and nothing is written; you can always add a station manually in the config (see Configuration).

Local files

Type local: followed by a path — or just paste a path starting with /, ~, or ./ — into the search box to list local audio files in the left pane. A folder is scanned recursively (.mp3, .flac, .ogg, .opus, .m4a, .wav, .aac, .aiff, .wma); a single file lists just that file. The rows behave like any song result: Enter plays, a queues, f favs, and crossfade transitions work between local and YouTube tracks alike. Local tracks can be saved into local playlists, but they cannot be added to YouTube playlists.

To try it without pointing at your own library, download three public-domain example songs (Musopen recordings) and list them:

./scripts/download-example-songs.sh

Then search local:examples/music from the repo directory (or paste the absolute path).

Local playlists

Local playlists are independent of YouTube playlists — useful for collecting tracks before creating a real YouTube playlist.

The right-pane Playlist / Queue section manages the queue as a named playlist. It holds the playlist name field, the New / Save / Add / Remove buttons, and the Shuffle / Clear controls (the Mix and Fade- / Fade+ transition controls sit under Now Playing, next to the volume row):

  • New starts a fresh playlist: the queue is cleared (a playing track keeps playing and stays as the first row), the loaded playlist is detached, and the name field is emptied and focused so you can name the new one.
  • Save (also w) saves the queue exactly as a local playlist under the typed name — falling back to the loaded playlist's title, then Saved Queue — so removals and reordering done with d/j/k persist.
  • Add adds the selected track — the highlighted queue row, else the highlighted search song, else the playing track — to the local playlist named in the field; without a name it uses the loaded local playlist, or creates TUI Playlist.
  • Remove removes the selected track (same resolution as Add) from the loaded playlist: local playlists are edited on disk, YouTube playlists in your account.

The CLI

bester-ytm                          # launch the TUI
bester-ytm search "Artist Song" --limit 15    # search songs (1-25, default 10)
bester-ytm play search "Artist Song" --seconds 20
bester-ytm play video VIDEO_ID --seconds 20
bester-ytm play playlist PLAYLIST_ID --transition crossfade --fade 8

bester-ytm playlist build --from seeds.md --name "My Mix" --count 30 \
    --brief "high-energy openers" --allow-variants
bester-ytm playlist create PLAN_ID --privacy PRIVATE
bester-ytm playlist export PLAN_ID --format md

bester-ytm favorites import-tuiradio path/to/favs.md

bester-ytm auth login [--oauth] [--no-browser]
bester-ytm auth status
bester-ytm auth logout --yes
bester-ytm config show
  • --seconds on the play commands plays a sample of that length, then exits.
  • playlist build takes --brief for a free-form prompt or constraints and --allow-variants to permit obvious live/remix/cover candidates.
  • auth login --no-browser (with --oauth) skips opening the web browser automatically; auth logout --yes skips the confirmation prompt.
  • play playlist requires a login even for public playlist ids, because it fetches the playlist through the authenticated client.
  • --transition and --fade override the saved configuration for one run; without them, play playlist uses the settings from config.toml.