- Go 98.8%
- Makefile 1.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Search the songs tab with yt-dlp, preview like a local mix, and store watch URLs in the usual m3u so resume works. mpv uses itag 18 and the android player client to avoid googlevideo 403s. |
||
| cmd/mix | ||
| internal | ||
| .gitignore | ||
| go.mod | ||
| go.sum | ||
| Makefile | ||
| README.md | ||
mix
Generate a random playlist from a local (or NFS) music library, preview it in
the terminal, and play it with mpv. Quit halfway through and
mix will offer to resume at the same track and timestamp.
Install
make install
Puts the binary in ~/.local/bin/mix. Requires Go 1.25+ and mpv on PATH.
Usage
mix # resume an unfinished mix, or generate a new one
mix new # always generate
mix resume # resume the current mix
mix list # archived mixes
mix show [NAME] # tracks in a mix (current if omitted)
mix play NAME # play a saved mix (id or name)
mix save [name] # name the current mix
mix index # rebuild the file index after you add albums
mix yt QUERY # search YouTube Music and play
Flags:
-n, --count N tracks per mix (default 50)
--root PATH music library root
--refresh rebuild the index before generating
--allow-repeats-album allow more than one song from the same album
On generate, mix prints a numbered Artist / Album / Title table and asks
[a]ccept [r]eroll [q]uit. Accept writes a timestamped .m3u (never
overwritten) and optionally names it, then starts mpv.
YouTube Music
mix yt searches YouTube Music's songs tab (not generic video search),
previews the same table, and on accept writes watch URLs into an .m3u.
mpv re-extracts those URLs at play time via yt-dlp. The query is all remaining
arguments, so you do not need quotes:
mix yt stars of the lid
mix yt -n 5 laufey from the start
Reroll shuffles the search pool (about 40 songs) and shows another n tracks
(default 10). Resume, mix play, and mix show work the same as local mixes.
Requires yt-dlp on PATH. YouTube currently 403s audio-only formats; mix
tells mpv to use muxed itag 18 and player_client=android. Override in
config.toml if that breaks:
ytdl_format = "18"
ytdl_extractor_args = "youtube:player_client=android"
One-off, without mix — quote the search, or the shell splits on spaces
and mpv searches for stars (Simply Red, nursery rhymes, …):
mpv --no-video --ytdl-format=18 \
--ytdl-raw-options-append=extractor-args=youtube:player_client=android \
'ytdl://ytsearch1:stars of the lid'
ytsearch1: is YouTube video search (full albums often win). Prefer mix yt
for actual songs.
Config
Optional ~/.config/mix/config.toml:
music_root = "/srv/nfs/rimsky/music"
count = 50
max_bytes = 83886080
extensions = ["mp3", "m4a", "flac", "ogg", "opus", "wav", "aac"]
Files larger than max_bytes (default 80 MiB) are treated as DJ mixes / films
and skipped. Video extensions are never included.
The file index lives in ~/.cache/mix/index.json and is rebuilt only when
missing or when you run mix index / --refresh. Playlists live in
~/.local/share/mix/playlists/.
Resume
mpv's own watch-later is per-file and does not restore playlist position, so
mix talks to mpv over a local IPC socket and writes ~/.local/share/mix/session.json.
A mix is finished only if you listen through the last track; quitting on that
track still counts as unfinished.