Skip to main content

Yt2Cli

A simple command-line (CLI) tool for searching and playing YouTube videos directly from the terminal, without needing to open a browser.

Features

  • Search YouTube videos by keyword, with an optional result limit (--limit=<n>, default 10)
  • Filter results by duration with --type=short|long|both (both applies no filter); cards show a Short badge for videos of 3 minutes or less
  • Browse a channel's videos by its YouTube handle: channel <channeluser> (supports --limit=<n> and --thumbs=yes|no)
  • Load videos from a YouTube playlist URL: playlist <url> (supports --limit=<n> and --thumbs=yes|no)
  • Results are cached per query and options (limit, type, thumbs), so re-searching the same keyword is instant
  • Load more results from the last search with more
  • Display search results as formatted video cards (title, channel, views with K/M/B suffix, duration, and Short/Normal/Not-a-video badge) with the video thumbnail rendered as block/pixel art; cards flow into a responsive multi-column grid based on terminal width. Disable thumbnail rendering with --thumbs=no for faster results
  • Play any video from the list through mpv, VLC, or ffplay — whichever is found first — falling back to the system's default application if none are installed
  • Play a video directly by URL without searching: open --url=<youtube-url>
  • Type a YouTube URL directly at the prompt to play it automatically, no command needed (recognizes youtube.com/watch, youtu.be, /shorts/, and /embed/ links)
  • Download one or more videos to an existing folder with --path=<existing-dir>: download <id1> <id2> ... --path=~/Videos, or download all loaded videos with download all --path=~/Videos, including direct URLs: download --url=<youtube-url> --path=~/Videos
  • Copy a video's URL to the clipboard with copy <id> (uses pyperclip)
  • Clear the in-memory cache and the loaded list with reset or cache:clear
  • Any unrecognized command is treated as a search query
  • Command line editing and history via readline
  • Cross-platform: works on Windows, macOS, and Linux

Requirements

1. Python

Recommended version: Python 3.10 or newer.

2. ffmpeg for downloads

Downloads fetch the best video and best audio streams separately and merge them with ffmpeg. Install it with your package manager (e.g. sudo dnf install ffmpeg, sudo apt install ffmpeg, brew install ffmpeg) or grab it from ffmpeg.org.

3. mpv / VLC / ffplay for playback (optional)

Videos play through the first of these players found on your system: mpv (preferred), VLC, or ffplay. If none is installed, the app falls back to opening the stream URL with the system's default application — this fallback can't send custom HTTP headers, so playback may fail (HTTP 403) for some videos.

Installing mpv:

OS Command
Fedora sudo dnf install mpv
Ubuntu / Debian sudo apt install mpv
macOS (Homebrew) brew install mpv
Windows Download from mpv.io

Installation

pip install yt2cli

Usage

yt2cli

This launches an interactive prompt. Type a command and press Enter.

To print the installed version without launching the prompt:

yt2cli --version

Available Commands

Command Description
channel <user> Browse a channel's videos by its YouTube handle; supports --limit=<n> and --thumbs=yes|no
playlist <url> Load videos from a YouTube playlist URL; supports --limit=<n> and --thumbs=yes|no
show Show the currently loaded videos from the last search
open <id> Play a video from the list by its number; use open --url=<youtube-url> to play a direct URL
download <id> Download one or more videos from the list to an existing folder (download <id1> <id2> ... --path=<existing-dir>), or all videos with download all --path=<existing-dir>; use download --url=<youtube-url> --path=<existing-dir> for a direct URL
copy <id> Copy the URL of a video from the list to the clipboard
more Load more videos from the last search (adds 5 more results)
reset Clear the loaded video list and the backend cache
cache:clear Clear all cached results (searches, channels, playlists)
clear Clear the terminal screen
help Show a list of available commands
exit Close the app

Note: Any input that isn't a recognized command is treated as a search query. A direct YouTube URL (youtube.com/watch, youtu.be/..., /shorts/..., or /embed/...) is played automatically instead of being searched.

Example

==================================================
                  AVAILABLE OPTIONS
==================================================
  [channel]  Browse a channel's videos by its YouTube handle
  [copy]  Copy a video's URL to the clipboard (ID required)
  [open]  Play a video from the list by its ID
  [clear]  Clear the terminal screen
  [show]  Show the currently loaded videos
  [exit]  Exit the application
  [help]  Show available commands
  [reset]  Clear the video list and backend cache
  [cache:clear]  Clear all cached results (searches, channels, playlists)
  [more]  Load more results from the last search
  [download]  Download a YouTube video
  [playlist]  Load videos from a YouTube playlist URL
  ==================================================

Yt2Cli Run: python tutorial --type=both
Searching...
Results for: python tutorial (limit=10, type=both, thumbs=yes)
 ──────────────────────────────────────────────────────────────
 ┌─────────────── block art ───────────────┐  [0] Python Basics for Beginners
 │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │      Programming Academy
 │ ░░░░░░ ░░ ░ ░  ░░   ░  ░░░ ░░░ ░░ ░░░  │      2.34M views
 │ ░ ░░░░ ░ ░░ ░ ░ ░░ ░ ░░ ░ ░░░ ░ ░░░░░  │      18:42 duration
 │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │      Normal video
 └─────────────────────────────────────────┘
 ──────────────────────────────────────────────────────────────

# The number in [brackets] is the video's index in the list (used by `open`/`download`/`copy`), not the YouTube video ID

Yt2Cli Run: open 0

Video Card Layout

Each search result is printed as a card:

 ──────────────────────────────────────────────────────────────
 ┌─────────────── block art ───────────────┐  [0] Python Basics for Beginners
 │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │      Programming Academy
 │ ░░░░░░ ░░ ░ ░  ░░   ░  ░░░ ░░░ ░░ ░░░  │      2.34M views
 │ ░ ░░░░ ░ ░░ ░ ░ ░░ ░ ░░ ░ ░░░ ░ ░░░░░  │      18:42 duration
 │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │      Normal video
 └─────────────────────────────────────────┘
 ──────────────────────────────────────────────────────────────
  • The card is bounded by a horizontal line (─)
  • Left side: the video thumbnail rendered as terminal block/pixel art (~40 columns wide) via term-image; when thumbnails are disabled (--thumbs=no) or unavailable, a dashed placeholder box is drawn instead
  • Right side: the bold [index] Title (truncated to 45 chars), the channel (truncated to 40 chars), the view count formatted with K/M/B suffixes, the video duration, and a video-type badge: Short (3 minutes or less), Normal (longer), or Not a video (entries without a duration, such as live or upcoming streams)
  • Cards are laid out in a responsive grid — as many cards per row as the terminal width allows, and each card is padded so columns align
  • The [index] is the card's position in the loaded list — the number you pass to open <id>, download <id>, or copy <id>

You can also play a video directly by URL, without searching first:

Yt2Cli Run: open --url=https://www.youtube.com/watch?v=id

Or simply type the URL itself — it will be detected and played automatically (youtube.com/watch, youtu.be/..., /shorts/..., and /embed/... links are recognized):

Yt2Cli Run: https://www.youtube.com/watch?v=id

You can also browse a channel's videos directly by its YouTube handle:

Yt2Cli Run: channel MrBeast --limit=5

You can also load videos from a YouTube playlist URL:

Yt2Cli Run: playlist https://www.youtube.com/playlist?list=PLxxxx --limit=5

Project Structure

yt2cli/
├── src/
│   └── yt2cli/
│       ├── __init__.py      # Exports the Yt2cli app and __version__
│       ├── App.py           # Core logic and command handling
│       ├── Backend.py       # Search logic (yt-dlp), result caching, and downloads
│       ├── Logger.py        # Custom yt-dlp logger (silences debug/warnings, prints errors)
│       ├── ParamManager.py  # Parses `--option=value` arguments for commands
│       ├── Player.py        # Video playback (mpv/VLC/ffplay with system fallback)
│       ├── SearchResults.py # Renders the video cards and thumbnail block art
│       ├── __main__.py      # python -m yt2cli entry point
│       └── cli.py           # Interactive REPL entry point

Notes

  • The app uses yt-dlp to search and extract video playback URLs.
  • channel <channeluser> loads a channel's videos from its /videos tab using the channel's YouTube handle (@handle or just handle); it accepts --limit=<n> and --thumbs=yes|no, and results are cached per channel and options.
  • playlist <url> loads videos from a YouTube playlist URL; it accepts --limit=<n> and --thumbs=yes|no, and results are cached per playlist and options.
  • Search, channel, and playlist results are cached in memory per URL/query and options (limit, type, thumbs); cache:clear empties this cache, and reset also clears the loaded video list.
  • Playback details: mpv receives the YouTube URL directly (resolving streams itself via its yt-dlp integration), while VLC/ffplay are handed separately resolved best-video/best-audio stream URLs along with the required HTTP headers; the system-default fallback opens a resolved combined-stream URL instead.
  • --type=short|long|both applies YouTube's duration filters to search results: short requests short-length videos, long requests longer ones, and both applies no filter. The Short badge shown on cards marks videos of 3 minutes or less.
  • --thumbs=yes|no (also accepts true/false) toggles whether search results render the video thumbnail as block art; no skips fetching thumbnails for faster results.
  • more re-searches the last query with a higher limit (adds 5 results each time).
  • download <id> --path=<existing-dir> saves the video with yt-dlp into the given existing folder. The folder must already exist and is passed with --path. It accepts multiple ids at once: download 0 2 5 --path=~/Videos. Use download all --path=<existing-dir> to download every video currently loaded. Videos are saved as the best video and best audio streams merged by ffmpeg.
  • copy <id> copies the video's URL to the clipboard via pyperclip.
  • open --url=<youtube-url> plays any video directly by URL, without needing to search for it first.
  • download --url=<youtube-url> --path=<existing-dir> downloads any video directly by URL, without needing to search for it first.
  • Typing a YouTube URL (youtube.com/watch, youtu.be/..., /shorts/..., or /embed/...) directly at the prompt plays it automatically.

License

MIT

Metadata

Release files for yt2cli 1.0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for yt2cli 1.0.2
File Size Uploaded
yt2cli-1.0.2.tar.gz 18.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for yt2cli 1.0.2
File Interpreter ABI Platform
yt2cli-1.0.2-py3-none-any.whl Python 3 none any Details

Total release size: 34.0 kB

Release files / yt2cli-1.0.2.tar.gz

Download URL yt2cli-1.0.2.tar.gz
Size 18.3 kB
Tags Source
SHA-256 checksum
How to use checksums
a8cd8994bc0a5215c06032fa7c88e4285dc303dc2a74b07e380e1b95aff8065b
BLAKE2b-256 checksum
How to use checksums
4c96790c3067d9e8441c990e99a990d15c2db0fa351225a5aaa3abbc9e45bd5a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.

Transparency log

Release files / yt2cli-1.0.2-py3-none-any.whl

Download URL yt2cli-1.0.2-py3-none-any.whl
Size 15.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
aa3edbe3cc1c7bc3430e467d4b3048f0d82b0d1b65872a5c370714fe7ee02063
BLAKE2b-256 checksum
How to use checksums
2d6896972c6a89322f930d7786ec308c3108f622bdcd4544c70a1a0153016241
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.0.2 This release

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.2.9

2 release files

0.2.8

2 release files

0.2.7

2 release files

0.2.6

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page