TypeScriptNode.jsSQLiteCLI
vault
Private
About the Project
A fully terminal-native music client for YouTube Music — search, stream, download, tag, and browse an entire music library without ever leaving the command line.
Overview
vault treats the terminal as a real music app rather than a script wrapper. It searches YouTube Music's catalogue, streams audio directly through mpv with no video and no browser involved, saves tracks locally as tagged .m4a files, and organizes a personal library by genre and freeform tags — all through either a menu-driven interactive TUI or direct scriptable CLI subcommands.
How It Works
- Search pulls results from YouTube Music via
musicstream-sdk(Innertube/YouTubei.js), rendered as a tabular picker with right-aligned durations and width-aware truncation - Stream spawns
mpv --ytdl --no-video --no-terminaldirectly against a YouTube URL — playback is headless and non-blocking, with stdin set to raw mode so a singleqor Ctrl+C kills the process cleanly and restores the terminal - Save downloads the best available audio via
yt-dlp -f bestaudio, storing files under~/Music/vault/{genre}/while recording metadata in a local SQLite database - Tag attaches freeform labels to saved tracks in a separate table with a foreign key back to the tracks table, enabling filtered library browsing (
vault library --tag "favourite") - Interactive mode wraps all of this in an
@inquirer/prompts-driven menu — arrow-key navigation throughout, a persistent now-playing indicator in the header, and a screen that clears between actions instead of stacking scroll history
Design Details Worth Noting
- Security-first process spawning — every child process call uses array-based arguments (
execFileSync/spawnwithshell: false), eliminating shell string concatenation and any command-injection surface entirely - Clean warning suppression — Node's
ExperimentalWarning(fromnode:sqliteviamusicstream-sdk) andDeprecationWarning(from shell-less spawning) are intercepted at the entry-point shim before any module code runs, so the CLI output stays clean without silencing warnings globally - Schema migration on rename — when the project renamed its backing service, the database schema migrated the primary identifier column (
audius_id→video_id) automatically on first run, with no manual intervention required for existing libraries
Tech Stack
Node.js (TypeScript, via tsx, no build step) · commander · @inquirer/prompts · musicstream-sdk · yt-dlp · better-sqlite3 · mpv · chalk · ora
Usage
# Interactive mode
npm start
# Direct CLI
vault search "Mac Miller"
vault save dQw4w9WgXcQ
vault play 42
vault tag 42 "chill"
vault library --genre "Hip-Hop"