ytcs

ytcs.sh fetches YouTube channel feeds, lets you browse them with fzf, and plays videos with mpv and yt-dlp, so you can watch through your normal browser cookies instead of using the YouTube site.

If what you want is “show me my subscriptions, let me search quickly, and play things in mpv”, that is what this script is for.

Video of ytcs in action

What it does

Requirements

For normal use you need:

Useful extras:

curl is the preferred fetcher when both curl and wget are installed.

Installation

Clone the repository from GitHub or GitLab and make the script executable if needed:

git clone <repo-url>
cd ytcs
chmod +x ytcs.sh
cp ytcs.env.example ytcs.env

Then edit ytcs.env if you want to change defaults.

If you create a local ./cache directory beside the script, ytcs will use that. Otherwise it falls back to ${XDG_DATA_HOME:-$HOME/.local/share}/ytcs.

Quick start

These commands should give you a good idea of how ytcs works and what it can (and cannot) do.

Play a single video directly:

./ytcs.sh 'https://www.youtube.com/watch?v=rveUASDFk58'

Subscribe to a channel:

./ytcs.sh --addsub https://www.youtube.com/@complexly

Refresh cached feeds:

./ytcs.sh --refresh

Browse in time order:

./ytcs.sh --time

Browse without Shorts:

./ytcs.sh --time --noshorts

Subscribe to a second channel:

./ytcs.sh --addsub https://www.youtube.com/@pbsspacetime

Refresh cached feeds:

./ytcs.sh --refresh

Browse by subscription:

./ytcs.sh --subscription

Launch the interface inside kitty (if kitty is installed):

./ytcs.sh --kitty --time

Browse and send the selected video to the default Chromecast using catt, if installed.:

./ytcs.sh --kast --fancy --time

Usage

ytcs uses a mix of flags and positional arguments:

Playing one video

If you pass a URL directly as the first non-option argument, ytcs hands it off to playback. This is the simplest mode:

./ytcs.sh 'https://www.youtube.com/watch?v=VIDEO_ID'

That also updates the local watched cache after playback.

If you want to cast instead, add --kast / -k. That always sends the full URL to catt cast. Check out and get catt at its repository. ytcs will send to the default configured device only.

Browsing subscriptions

There are three main subscription views:

Grouped and chronological views support multi-select queueing with Tab.

Videos detected as vertical content use V_GEOMETRY1 / V_GEOMETRY2 when available. That currently covers feed entries marked as Shorts and direct URLs that look like YouTube Shorts, TikTok, or Facebook video links.

Importing subscriptions

Import a CSV export like this:

./ytcs.sh --import /path/to/subscriptions.csv

The CSV should use the usual channel export shape: channel id, URL, channel name, with no trailing comma. The included sample matches the format FreeTube exports.

The path after --import is positional, so keep it immediately after the switch.

Adding one subscription directly

You can add a channel from either a handle URL or a /channel/... URL:

./ytcs.sh --addsub 'https://www.youtube.com/@kurzgesagt'

Handle resolution uses the YouTube Data API, so YTUBE_API_KEY must be set in ytcs.env for @handle inputs.

The URL after --addsub is positional, so keep it immediately after the switch.

Command line options

If you run ytcs.sh with no arguments, it opens an fzf launcher for the main actions.

Positional argument rules:

fzf behavior

Video previews can show:

In --kitty mode, the UI is relaunched inside kitty and the preview pane moves below the list.

In --fancy mode, the main UI stays in the normal layout, but preview rendering still gets kitty-style behavior. This can be handy, but it is also the mode most likely to behave oddly in tmux, nested terminals, or terminals that only partially support kitty graphics.

Configuration

The defaults from ytcs.env.example are:

export MAX_CHANNEL_AGE=182
export MAX_GROUPED_VIDS=10
#export watchtop=4
export LOUD=0
export YTDLP_COOKIES="firefox"
export MARK_AGE="TRUE"
export GEOMETRY1="1366x768+50%+50%"
export GEOMETRY2="1366x768"
export V_GEOMETRY1="450x800+50%+50%"
export V_GEOMETRY2="450x800"
# This is if you have a special case for the provider server being on a
# nonstandard port or machine ONLY, see https://github.com/Brainicism/bgutil-ytdlp-pot-provider?tab=readme-ov-file#usage
export YTPOT_BASEURL="youtubepot-bgutilhttp:base_url=http://127.0.0.1:8080"
export YTUBE_API_KEY=""

The settings you are most likely to care about are:

Notes

This script is for personal use. Make sure your usage complies with YouTube’s terms and with the wishes of the creators whose videos you are watching.

License

MIT