CLI tool
peternaame-boop/ytm-player avatar
peternaame-boop/ytm-player

ytm-player: YouTube Music in the terminal with vim keys and synced lyrics

YouTube Music TUI client with vim keybindings, synced lyrics, and cross-platform media keys

529 stars46 forksPythonMIT

At a glance

What is it?
ytm-player is a Textual based terminal client for YouTube Music that plays through mpv, syncs lyrics with an LRCLIB fallback, and can be driven from another terminal over IPC. It suits keyboard-first users who want their music player to obey the same keys as their editor, and it depends on mpv being installed system-wide.
Who is it for?
ytm-player suits someone who already lives in a terminal, plays YouTube Music and wants vim style navigation with a second monitor or a second shell for controlling playback, and it does not suit a listener who wants a native desktop player, an offline library or a supported media player.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 13 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A terminal client that treats mpv as the sound card

ytm-player is a YouTube Music TUI client, which is a specific and unusual thing to build: a full music streaming client inside a terminal, with the streaming and authentication handled in Python and the audio handled by a separate program.

The architecture is split along a sensible line. The user interface is a Textual application, the streaming layer is ytmusicapi, the download side is yt-dlp, and the audio playback is python-mpv, which drives the external mpv binary. The readme lists mpv as the audio playback backend and says it must be installed system-wide, and mpv is called out in the feature list for gapless audio, stream prefetching and broad codec support.

That split is what makes the gapless and prefetch behaviour possible without reimplementing a decoder. mpv is a mature media player that already handles codecs and audio devices, and the client hands it URLs and properties. The price is a dependency outside Python, which is why the requirements section lists mpv alongside Python 3.10 or newer and a YouTube Music account.

The account requirement is worth stating plainly, because it defines the scope of the project. A YouTube Music account, free or Premium, is required, and the readme also says the free tier is supported, so a subscription is not needed. That is a real constraint compared with a local music library: this is a client for one streaming service, not a general purpose player for your own files.

The interface itself is vim-flavoured. The feature list names j and k for movement, multi-key sequences such as g s for search and g l for library, and count prefixes such as 5j. Those are the conventions of a modal editor, applied to a media browser, and it is the single clearest signal of who the tool is for.

Synced lyrics that fall back to LRCLIB

The lyrics feature is the most substantial piece of engineering in the project, and the way it is described gives a good sense of the effort behind it.

Synced lyrics are live-highlighted, with an LRCLIB fallback for tracks YouTube does not have, and there is title sanitization for better LRCLIB matches. That last clause is the interesting one, because it describes a data cleaning problem. YouTube Music track titles carry decorations, and a title that a lyric service has never seen will not match. Sanitizing the title before querying is the difference between a lookup that works on a fraction of tracks and one that works on most of them.

The fallback design also implies something about the priority. The primary source is YouTube's own synced lyrics, and LRCLIB fills the gap. That ordering makes sense: the service that has the track is the most likely to have the timing data for it, and the open database catches the rest.

The other features in the same list are more conventional but still worth naming, because they say what kind of completeness the project aims at. There is a local cache, described as an LRU audio cache for offline-like replay of previously heard tracks. There is session resume, restoring the last playing track and the queue on launch. There is Spotify import, pulling playlists in through the API with a scraper fallback. And there is Discord Rich Presence plus Last.fm scrobling.

The Spotify import with a scraper fallback is a good example of the project's character. The API is the supported path, and the scraper exists for when the API does not give you what you want. A scraper is the fragile option, so having it behind the API rather than instead of it is the right order.

The theme support is also notable for a terminal application. There are more than 18 Textual themes, plus per-app colour overrides in a theme.toml file, so the client can be made to match the rest of your terminal setup rather than looking like a foreign object in it.

Driving the player from a second terminal

The CLI plus IPC entry is the feature that makes this more than a single-window toy, and it is easy to miss in a feature list full of visual details.

The readme lists CLI and IPC: control a running TUI from another terminal, with commands such as ytm play and ytm pause. The point is that the player can keep running in one terminal while you send it commands from another. On a multi monitor setup, or with a tmux pane, that means the player lives in its own window and the controls are typed wherever you happen to be.

The documentation table confirms the surface area is treated as a first class interface. There is a separate document for all ytm CLI subcommands, a separate one for the full keyboard and mouse keybindings, a separate one for the config.toml and theme.toml reference, and separate ones for Spotify playlist import, for troubleshooting, and for the file layout and stack.

That is an unusually well organised documentation set for a project of this size, and the troubleshooting document is telling. Its listed topics are mpv, auth, MPRIS, macOS and cache, which are exactly the five places where a cross platform media client breaks: the external binary is missing, the login did not stick, the Linux media control interface is not talking to the player, the macOS integration is missing, or the cache is not doing what you expected. Knowing which five things break is a sign the author has seen them break.

The install step and the quickstart are two commands.

bash
ytm setup    # one-time auth (auto-detects browser cookies)
ytm          # launch the TUI

The setup step does the authentication once and auto-detects browser cookies, and then the second command launches the interface. On Windows the readme says to replace ytm with py -m ytm_player.

The platform integrations are the other half of that story. There is MPRIS on Linux, Now Playing on macOS, and media keys on Windows, so the hardware keys on your keyboard drive the player on all three systems.

The cookie extraction path is the part to read carefully

The dependencies list in pyproject.toml contains a comment that is worth reading twice, because it explains a design decision that would otherwise look arbitrary.

The comment notes that yt-dlp treats pycryptodomex as optional and falls back to a pure-Python AES implementation without it. The comment says that is fine for occasional use, but that browser cookie extraction, in the AuthManager's _extract_and_save and _extract_and_save_from_cookies_file functions in services/auth.py, decrypts a whole browser cookie store at once. The numbers given are about 26 seconds with the pure-Python fallback against about 2.4 seconds with pycryptodomex's native AES, for a Chromium based profile with roughly 3500 cookies.

So the reasoning is visible: the dependency is there for speed on a specific operation, and the operation in question is unlocking your browser cookie store.

That is worth thinking about as an adopter. The project reads cookies from your browser to authenticate against YouTube Music, which means it needs access to a credential store that the operating system normally protects, and it extracts it in bulk rather than asking for one value. The readme does not describe a security model for this, and the SECURITY.md file it links to is where that would live if it is described at all.

The project is MIT licensed, which is a permissive licence, and the licence field on the repository and in the package metadata both say MIT. The publisher is listed as Peter with a Gmail address, and the package is marked Development Status :: 4 - Beta, which is an honest signal about where the project is. The last push was on 2026-10-10, and the recent releases are v2.1.0 from 2026-09-08, v2.0.0 from 2026-07-04 and v1.9.5 from 2026-06-28, so it is moving quickly and has crossed a major version recently.

Because it moves fast, the CHANGELOG.md file and the RELEASING.md file are in the repository root, and the readme points at the changelog for the full release history. For a project that rewrites its own dependency versions, that file is part of the adoption decision.

Where ytm-player is the wrong tool

There are four cases where this is the wrong choice, and none of them are about quality.

The first is a local music library. ytm-player streams from YouTube Music. If your music is on disk, or on a self hosted server, or in a lossless library you care about, this client has nothing to say about it. Its entire value is the interface to one specific service, and the local cache is described as an LRU cache for offline-like replay of previously heard tracks, which is a cache, not a library.

The second is a headless or minimal environment. This is a TUI with a real interface, an mpv process and a Python runtime. On a server with no audio device and no terminal, none of that is useful.

The third is a user who wants a supported player. A Beta stage package maintained by one person, with a YouTube Music account and browser cookies as the authentication mechanism, is not something to build a dependency on for a household. The readme does say it is actively maintained with cross-platform support, and the release cadence is fast, but a fast cadence is also a fast pace of change, and v2.0.0 landed in July 2026.

The fourth is a YouTube Music user who wants the official app's features. The readme does not claim parity, and a terminal client is not going to have the recommendations, offline downloads, casting and account sync that a first party client has.

On the alternative, the comparison with a browser tab plus a desktop client is the honest one. A browser tab and a native app give you a polished interface, background playback, and no dependency to install, and the browser is already where your YouTube account is authenticated. What you give up is the keyboard-driven workflow: a modal interface where j and k move through a list and g s jumps to search, and the ability to send a play command from another terminal. For a lot of people that is the whole point of the tool, and for a lot of other people it is not.

The other comparison is with the ecosystem of terminal media players built on mpv. There is a well established set of those, and the difference in approach here is that ytm-player adds a full streaming service client with authentication, synced lyrics and a remote control channel on top of the player rather than being a thin mpv front end. The trade is that a thinner client has fewer moving parts to break, and this one has an account, a cookie store and a scraping path to maintain.

Editorial conclusion

ytm-player suits someone who already lives in a terminal, plays YouTube Music and wants vim style navigation with a second monitor or a second shell for controlling playback, and it does not suit a listener who wants a native desktop player, an offline library or a supported media player. Before you install it, confirm mpv is available on your system, because the readme says it must be installed system-wide, and read the security policy and configuration reference, since the client authenticates with your YouTube Music account and the browser cookie extraction path is the part most likely to surprise you.

Frequently asked questions

What is ytm-player?

It is a YouTube Music terminal client built with Textual, using vim style keybindings, synced lyrics with an LRCLIB fallback, mpv for audio playback and a CLI that can control a running instance from another terminal.

What do I need to install ytm-player?

Python 3.10 or newer, mpv installed system-wide as the audio playback backend, and a YouTube Music account, free or Premium. The package itself installs with pip install ytm-player, and there are also AUR, NixOS and Gentoo packages.

How do I set up ytm-player?

Run ytm setup for one-time authentication, which auto-detects browser cookies, then run ytm to launch the terminal interface. On Windows you replace ytm with py -m ytm_player.

Does ytm-player need YouTube Music Premium?

No. The readme states free tier support, so it works without YouTube Music Premium, though a YouTube Music account is required either way.

How does ytm-player show synced lyrics?

It highlights lyrics live using YouTube's own synced lyrics, and falls back to LRCLIB for tracks YouTube does not have, with title sanitization to improve the LRCLIB match rate.

Official sources

  1. License: MIT
  2. peternaame-boop/ytm-player on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/peternaame-boop-ytm-player.svg)](https://hysenlabs.com/projects/peternaame-boop-ytm-player)

Was this useful?