You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Local audio file playback: type local: plus a path — or simply paste a
path starting with /, ~, or ./ — into the search box and the audio
files there (folders are scanned recursively) appear in the left pane as
regular song rows. Enter plays, a queues, f favs, local playlists
can hold them, and DJ crossfades blend local and YouTube tracks
interchangeably. ./scripts/download-example-songs.sh fetches three
public-domain example songs into examples/music/ to try it out.
g takes a digit count for similar tracks: g alone queues the default
number of AI-suggested similar songs, g11 queues eleven (up to 30), and
Escape cancels the pending count.
Favorites as a first-class feature: f favs or unfavs the highlighted
song (falling back to the playing track), faved songs show a trailing *
in the queue, search results, and the Now Playing label, and a favs:
search prefix lists them (favs:text filters). Favorites persist as full
track records in favorites.json; entries from the legacy favorites.md
are migrated on first use.
Album search as an expandable tree: album: queries render album titles
in the left pane; Enter expands an album (its songs load in the background
on first expand), a adds an album, song, or the marked rows to the queue,
and A (shift+a) plays the album now — from the top or from the
highlighted song on.
Range selection in search results and the album tree: Shift+Space and
shift+click mark every song from the first marked one through the
highlighted row.
A dedicated Playlist / Queue section in the right pane: a playlist name
field with New / Save / Add / Remove buttons plus the Shuffle / Mix /
Clear and Fade- / Fade+ controls. New starts a fresh playlist while the
playing track keeps playing, and freshly built or saved playlists appear
in the left library immediately.
A keyboard help overlay: ? opens a modal listing every key binding,
grouped by purpose; Escape, q, or ? closes it.
Login state at startup: the status line reports Logged in to YouTube Music. or a hint to run bester-ytm auth login;
the volume buttons moved into their own row under the transport controls.
Changed
The right pane got simpler: the Track Details section is gone, and the
Mix / Fade- / Fade+ transition controls moved from the Playlist / Queue
section into Now Playing next to the volume row, since they act on live
playback rather than the queue.
Playback status messages name the track instead of showing raw video ids,
including the remove, move, skip-unplayable, and mixing messages.
Deleting a local playlist with d now requires a confirming second press,
matching YouTube playlist deletion.
Search, playlist loading, YouTube library listing, and album expansion run
on worker threads, so slow YouTube Music responses no longer freeze the
TUI.
The visualizers lock their motion to the audible beat.
Internal: tui.py and ytm_client.py were split into focused modules
(tui_* action mixins; session, search, library, and models behind the ytm_client facade), and the test suite runs markedly faster.
Removed
Track ratings and tags: the Track Details section, the r key, and the
Rate- / Rate+ / Save Tags buttons are gone in favor of the simpler
favorites toggle. An existing track-metadata.json is left untouched on
disk but is no longer read.
Fixed
Browser login accepts headers pasted from Firefox, whose "Copy Request
Headers" separates lines with NEL characters that broke the old
line-by-line reader (and left Ctrl-D doing nothing). Input is now read to
EOF and normalized, and the guide says to click a song so a browse
request appears, then press Enter and Ctrl-D after pasting.
f favs the highlighted search result while the results pane has focus
even when a playlist is loaded; the queue's remembered selection no longer
hijacks the toggle.
The = (volume up) and . (seek +30s) keys were dead because the
bindings used the wrong Textual key names; both work again, and + also
raises the volume.
The periodic refresh tick redraws the Now Playing label only when the
track actually changes.
Variant filtering (live/remix/cover detection) matches whole words only,
so titles like "Alive" or "Deliverance" are no longer rejected as "live"
variants.
Deferred loads (search, playlist listing, album results) that finish while
you are typing in the search input or the builder text area no longer steal
the focus mid-keystroke.
a / A / x on a collapsed album fetch its tracks on a worker thread
and apply the action when they land, instead of freezing the TUI during
the fetch.
When pause falls back to process signals (mpv IPC unavailable), resume
works again, and status polling, seeking, volume, and mute no longer stall
against the signal-stopped mpv.
Corrupt store files (favorites, plans, local playlists) now produce
an actionable "move the file aside and retry" error that the TUI shows in
the status bar instead of crashing; corrupt local playlists are skipped
with a warning when listing.
Retiring a crossfade deck no longer blocks playback: decks terminate in
the background and are force-killed after a 5-second grace period.
bester-ytm search --help now shows a description of the command.