CLI tool
Benexl/yt-x avatar
Benexl/yt-x

yt-x, a POSIX shell front end that turns yt-dlp into a browsable menu

Posix script to browse youtube plus other yt-dlp supported sites from your terminal (fzf) or app launcher (rofi) with optional previews. (supports bash, zsh and dash)

1,680 stars79 forksShellMIT

At a glance

What is it?
yt-x is a shell script that lets you search and browse YouTube and other yt-dlp supported sites from a terminal with fzf or from a desktop launcher with rofi, with previews, inline filters and extension based theming. It wraps yt-dlp rather than replacing it.
Who is it for?
Adopt yt-x if you already use yt-dlp and want its sites as a searchable menu with previews, history recall and themed prompts, and if you are comfortable with a shell script that depends on fzf, jq, curl and a media player being present. Do not adopt it expecting a self contained downloader, since the downloading and extraction is done by yt-dlp, and do not use it in a pipeline where a stable machine readable output matters, because the interface is an interactive menu.
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 3 days ago.
What is it written in?
Mainly Shell, according to GitHub's language statistics.

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

Editorial analysis

A shell script that puts a menu in front of yt-dlp

yt-x is a POSIX script for browsing YouTube and other yt-dlp supported sites from a terminal with fzf, or from an app launcher with rofi, with optional previews. It states support for bash, zsh and dash, and the primary language of the repository is Shell.

The division of labour matters for what you are actually adopting. yt-dlp does the extraction, and yt-x is the interactive layer above it: search, browse, pick, then hand off. That is why the tool can cover videos, playlists, channels, shorts and movies without reimplementing any of the site-specific extraction logic that yt-dlp maintains.

The audience is people who live in a terminal or a launcher and want to move from a typed query to a playing video without opening a browser. A keyboard driven flow is the point: type a few characters, see matching results, preview them, and play or download the one you want. Both supported launchers can render a preview pane next to the list, and the project ships a gallery of themed previews to show what that looks like in a configured desktop.

The constraint that follows from the design is that this is an interactive tool. Its output is a menu a human reads, not a list a script parses, and the script is written in shell, so its behaviour is shaped by what is installed on the machine.

Two launchers, and previews that work in both

The launcher is the primary interface, and the project supports fzf and rofi, with previews in both. That pairing is deliberate. fzf is the fuzzy finder you pipe a list into from a shell, and rofi is the desktop launcher that a window manager or a hotkey opens.

The same script serves both because the underlying data is the same. The search results, the channel listings, the feed entries and the playlist items are produced once and then handed to whichever picker the user has. A user who lives in the terminal and a user who wants a launcher popup can each use the same menus, the same filters and the same downloads.

The project description also mentions gum among the topics, alongside fzf, rofi, jq, curl, mpv and vlc, which is a reasonable summary of what a script like this leans on. jq for parsing the metadata that yt-dlp emits, curl for the network calls, and a media player for the playback step. Treating these as expected dependencies rather than bundled libraries is the shape of a POSIX script that has to run on whatever the user already has.

One consequence is worth spelling out. Because the picker is a separate program, the look and the key bindings of your browsing experience come from fzf or rofi and their own configuration, and the preview rendering likewise. The project customises the menu content and the theme, not the picker itself.

Colon-prefixed filters typed straight into the query

The most distinctive feature is that filters are not a separate mode or a menu. They are colon-prefixed tokens you type directly into the search query, and they are grouped by what they constrain.

Time filters are the first group.

bash
:hour
:today
:week
:month
:year
:video
:movie
:live
:short
:long

Type filters, feature filters and sort orders follow.

bash
:4k
:hd
:hdr
:subtitles
:360
:vr
:3d
:local
:newest
:views
:rating

So a query such as a channel name followed by :month and :live is read as a filtered search rather than as literal text, and the tokens are stripped before the query is sent on.

The design has a real advantage over a settings panel: the filter travels with the query, so it can be recalled, shared and repeated without reconfiguring anything. The cost is a namespace collision. A search for a literal term beginning with a colon is ambiguous, and the project does not document an escape mechanism, so a user whose content legitimately contains these tokens has to work around it.

It also puts the filtering capability in the shell layer rather than in yt-dlp, which means the filters are the script's own interpretation of the metadata rather than a filter the extractor performs.

Bang syntax for history, and direct flags to skip the menus

Search history is automatic, and previous searches are recalled with bang syntax: !1 for the most recent search, !2 for the second, and so on. It is a shell convention rather than an invented interface, so anyone who has used bash history expansion will recognise it immediately, and the numbering makes it possible to jump back several steps in one keystroke.

The same principle runs through the rest of the tool. There are scriptable shortcuts that bypass the menus and jump straight to a specific feed, search or action using direct command line flags. The idea is that a menu is good for discovery and a flag is good for automation, and you should not have to open a picker to get to a known destination.

YouTube feeds are the clearest case. The personal feeds are available, including the Home Feed, Trending, Watch Later, Liked Videos, Watch History and Clips, and channel browsing covers a channel's Videos, Featured content, Playlists, Shorts, Live Streams, Podcasts and search pages.

That combination, history plus direct flags plus feeds, is what makes the tool usable daily rather than as a one-off novelty. A person who has already watched something and wants it again uses the history or the Watch History feed, and a person who wants the same thing every morning uses a flag instead of clicking through a menu.

Download archiving, playlist queues and generated m3u8 mixes

The download side of yt-x is more opinionated than the browse side, and it is where the interesting file handling happens.

Granular downloads are supported: a single video, an entire playlist, or audio-only extraction in MP3 format. On top of that there is a download archive directory, which uses yt-dlp's download archive option to track previously downloaded media and prevent the same file being fetched again. In practice that means a playlist of fifty videos does not re-download the twenty you already have, which is the difference between a downloader you use daily and one you avoid.

Playlist actions go further. You can play an individual video, queue or play an entire playlist, or queue a Listen to All entry for audio-only playback. There is also auto-mix generation, which dynamically produces an m3u8 playlist mix from a single video, described in the project description as a replication of the YouTube Mix feature.

Player support covers mpv, vlc and tplay. Background playback is available as well, through the configuration variable CONFIG_DISOWN_PLAYER, which detaches the player process so closing the terminal does not stop the audio.

Downloads are routed into structured directories automatically, and the project describes this as automatic file organisation. The exact directory layout is defined in the configuration files under the configs directory, which is where you decide how your library is shaped.

Extensions carry the menus, the theme and the language

Customization in yt-x is done through three extension file types, and this is the part of the design that makes the tool fit a specific taste rather than a generic one.

The .ui extensions control the menus. You can reorder entries, add your own, or filter entries out, so the set of destinations in the interface is yours to define rather than a fixed list. The .theme extensions handle styling, with tokyo night as the default theme. The .lang extensions are language files that localise the prompts and messages in the UI, with es and br currently available and contributions for more languages welcomed.

The division into three file types is a good sign of design discipline. Menus, appearance and language change for different reasons and at different times, and keeping them apart means a theme change does not risk breaking a menu and a new language does not require touching the prompt logic.

The rofi-themes directory at the top level of the repository holds themes for the launcher side, and the gallery of preview images in the project description shows several riced and customised setups, which suggests the theme layer is expected to be edited rather than left alone.

The trade-off is that everything you configure is your own work. A theme you wrote is a theme you maintain, and a menu you removed is a menu you have to re-add when the tool changes.

A shell repository with nix, lua and changelog tooling alongside

The top level of the repository shows the shape of the project. The script itself is the yt-x file at the root, and there is a version.txt next to it, along with a LICENSE and a README.

The rest is infrastructure, and the interesting entries are the ones that show how the project is developed and distributed. A flake.nix and a flake.lock sit alongside a default.nix, so the script can be pinned and built through Nix, with a lock file recording exact revisions. A.envrc points at direnv for a local development environment, and a.lazy.lua is present, which is the shape of a lazy.nvim configuration, suggesting the project is consumed as a plugin by Neovim users as well as run from a shell.

For releases, a.cliff.toml configures git-cliff, the changelog generator, which is how a project with many small commits produces readable release notes.

The extension directories and configuration directories are the remaining pieces, and the repository also carries a dev directory for development scripts.

Maintenance is active by the numbers. The recent releases are v0.8.7 on 2026-10-01, v0.8.6 on 2026-06-07 and v0.8.5 on 2026-06-06, and the last push was on 2026-10-19. The repository is not archived, and the licence is MIT, so the script can be read, modified and redistributed without any disclosure obligation beyond keeping the copyright notice.

Editorial conclusion

Adopt yt-x if you already use yt-dlp and want its sites as a searchable menu with previews, history recall and themed prompts, and if you are comfortable with a shell script that depends on fzf, jq, curl and a media player being present. Do not adopt it expecting a self contained downloader, since the downloading and extraction is done by yt-dlp, and do not use it in a pipeline where a stable machine readable output matters, because the interface is an interactive menu. Before you start, read the prerequisites and universal installation sections of the project README, confirm your shell is bash, zsh or dash, and check that the player you want, mpv, vlc or tplay, is installed and on your PATH.

Frequently asked questions

What does yt-x need to run?

yt-x is a POSIX shell script that supports bash, zsh and dash, and it expects tools such as fzf or rofi for the picker, jq and curl for the data, and a player such as mpv, vlc or tplay. The project README documents prerequisites, a universal installation method and platform-specific instructions.

How do the inline search filters in yt-x work?

You type colon-prefixed tokens straight into the search query. Time filters include :hour, :today, :week, :month and :year, type filters include :video, :movie, :live, :short and :long, feature filters include :4k, :hd, :hdr, :subtitles, :360, :vr, :3d and :local, and sorting includes :newest, :views and :rating.

Does yt-x avoid re-downloading videos I already have?

Yes. It uses a download archive directory, built on yt-dlp's download archive option, to track previously downloaded media and prevent duplicate downloads. Downloads can be a single video, a whole playlist, or audio only in MP3 format.

Can I change the menus, the theme and the language in yt-x?

Yes, through three extension types. .ui extensions reorder, add or filter menu entries, .theme extensions handle styling with tokyo night as the default, and .lang files localise the UI prompts, with es and br currently available.

Which shells and launchers does yt-x support?

It supports bash, zsh and dash, and works with the fzf and rofi launchers, both of which can show previews. The current release is v0.8.7, dated 2026-10-01, under the MIT licence.

Official sources

  1. Benexl/yt-x on GitHub
  2. Issues
  3. License: MIT
  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/benexl-yt-x.svg)](https://hysenlabs.com/projects/benexl-yt-x)

Was this useful?