Overview

Written in Rust, the YouTube TUI is a lightweight and user friendly TUI for browsing YouTube content from the terminal. Works out of the box and easily to configurable.

It is like an app launcher, it launches other programs to do the heavy lifting (for example, mpv for playing videos).

It also have an embedded mpv music player, but that can be disabled in compile time.

Consider regenerating config files on updates to allow new features.

Customisable

The YouTube TUI can be customised through config files, they are located in ~/.config/youtube-tui and are in the YAML format.

Here's an example of the config file:

mouse_support: true
invidious_instance: https://vid.puffyan.us
max_watch_history: 50
allow_unicode: false
images: Sixels
refresh_after_modifying_search_filters: true
provider: YouTube
env:
  browser: firefox
  video-player: mpv
  youtube-downloader: yt-dlp
  terminal-emulator: konsole -e

Anything from layouts to colours and keybindings can be customised, more on that later.

Dependency-free*

See installation#features for more info on dependencies.

The YouTube TUI does not work on its own, it is instead like a TUI frontend for programs like mpv or yt-dlp/youtube-dl.

However, the programs to launch can be changed, and therefore the YouTube TUI does not rely on any specific dependencies to run.

Powerful

The YouTube TUI allows you to browse YouTube with (almost) all of it's features, functions including:

  • View information about channels, playlists and videos
  • Use search filters to sort and filter search results
  • Save browsing history
  • Embedded audio/music player

It also includes features like:

  • Vim-like commands
  • Mouse support
  • Extensible keybindings system
  • Offline library
  • Subscriptions

What it doesn't have

  • [URGENT] Replace the no-longer-going-to-compile typemap dependency with either a self implementation of it or a useable crate.
  • Strip down some libraries to reduce compile speed.
  • Add command section for channel main page (first priority)
  • Git like command line to improve on yt-dlp - make changes to existing downloaded playlists instead of redownloading the entire thing.

How to contribute

You will need a general knowledge of the Rust programming language, and the ability to understand my spaghetti.

  1. Open an issue to make sure nobody else is working on the same feature
  2. Write code
  3. Open a pull request
  4. Get merged?

Or just fix that typo in README -_-

Installation

The YouTube TUI is not intended for Windows, pull requests to make it work are welcome.

Crates.io is a repository for programs written in Rust, and the YouTube TUI is available there.

To install using this method, you will need rustc and cargo present. Here's a tutorial on how to get them.

Now, run the following command:

cargo install youtube-tui

To check and update all programs installed from Crates.io, you can use CLI tools like cargo-update.

The YouTube TUI is available in the AUR here.

Use an AUR helper like yay to install.

yay -S youtube-tui # lastest crates.io release, recommended
yay -S youtube-tui-git # latest git version, potentially untested
yay -S youtube-tui-full-bin # default binary (out of date)
yay -S youtube-tui-nodefaults-bin # minimal binary (out of date)

Add the following Nix code to your NixOS Configuration

environment.systemPackages = [
  pkgs.youtube-tui
];

Build from source

Use the cargo command:

cargo install --git https://github.com/siriusmart/youtube-tui

Confirm YouTube TUI has been installed

Run the following command in terminal:

youtube-tui

If installed correctly, a TUI should be launched. Press q to close the TUI.

Features

The TUI has features that can be enabled/disabled when compiling.

cargo install youtube-tui # install with all default features
cargo install youtube-tui --no-default-features # install without any features enabled
cargo install youtube-tui --no-default-features -F 'halfblock' # install with only HalfBlocks support (but not Sixels)
cargo install youtube-tui --no-default-features -F 'clipboard' -F 'sixel' # can install with multiple features by doing this
cargo install youtube-tui --all-features # install with all features (even if not included in default)

halfblock (default)

Display images through HalfBlocks, work best in terminals with TrueColour support.

sixel (default)

Display images with Sixels, allows the display of images at full definition. Not present on windows.

Enabling this will also enable halfblock.

Requires libsixel.

clipboard (default)

Allows clipboard pasting in commands and search bar.

Requires libxcb.

mpv (default)

Embedded audio player

Requires mpv (libmpv) to be installed in your system.

Basic usage

Here is a basic how-to guide on the TUI.

Cursor

The cursor can be moved using arrow keys, or Vim keybindings (hjkl).

The item with the cursor hovering will have a red outline.

Everything here refers to the latest default config, including the keybindings.

FunctionKey(s)
SelectEnter
DeselectEsc
Cursor upUp arrow / k
Cursor downDown arrow / j
Cursor leftLeft arrow / h
Cursor rightRight arrow / l
Previous pageBackspace / Alt + Left arrow
First page historyHome
Clear page historyEnd
Paste from clipboardCtrl + V
Next/previous entry on search and commandCtrl + up/down arrow
Next songCtrl + Shift + Right arrow
Seek audioCtrl + left/right arrow
Pause/resume audioSpace
Enter command mode:
Quitq

Selection

Selecting an item allows you to move the cursor within that item, to select an item, press Enter.

When nothing is selected, you can move the cursor between items, to deselect from an item, hit Esc.

Searching

Type the search query when the search bar and press Enter, use arrow keys to move the cursor around.

To apply search filters, select the button with 3 dots (...) to the right of the search bar, hit enter to start modifying and enter again to save. Pressing Esc should reload the current search page to apply the filters.

You may use Ctrl + Up/Down arrow to cycle through previously searched queries (when focused on the search bar).

Playing media with embedded player

By default, running any "play video" options in video or playlist view will open a new mpv player window.

While any "play audio" options will start playing the audio in the embedded audio player,

  • seek and rewind using Ctrl + Left/Right arrow
  • skip with Ctrl + Shift + Right arrow
  • pause and resume with space

Playing videos and playlists externally

You can also play audio and videos externally.

This part assumes that you use mpv as your video player, konsole as your terminal emulator, yt-dlp as your YouTube video downloader, and firefox as your browser.

If that is not the case, you can learn how to change that in the custom commands section.

You can press keybindings like Shift + A to run a command which opens a new terminal screen, and in that terminal screen it runs an mpv command to play the media.

Feeds

Feeds allows you to view updates from subscribed channels, similar to how subscriptions works on YouTube.

Command mode

Command mode is like that of Vim, it can be started by pressing : when nothing is selected.

More about commands in the next chapter.

Command bindings

Keys can be bind to a command, more about it in the next chapter.

For example Ctrl + F launches your web browser.

Buttons

Buttons are similar to hyperlinks, it allows you to navigate between pages.

Mouse click control

Mouse click controls has been added, you can now use your mouse to navigate around the TUI. Here are the general rules:

  1. Clicking an item moves the cursor to that item, clicking again selects the item
  2. Clicking on buttons, or items on a list has the same effect as pressing Enter on them
  3. Clicking outside a popup closes the popup

However, there are some downsides to not using your keyboard.

  1. Cannot move up or down to items not on screen in a list (you can do that with Up or Down arrow)
  2. Cannot access function keys like Backspace or Q

Library

Items can be bookmarked and saved to library, they can also be saved to be viewed offline.

Commands

Commands can be entered to the TUI by pressing the : key, the same as in Vim.

Run the help command to view more detailed help.

youtube-tui help

Env variables can be used by passing in as ${key}, such as :channel ${channel-id} when in a video or playlist page.

Loadpage commands can also be used when launching, for example youtube-tui loadpage popular or youtube-tui popular.

Commands can be joined together using ;;.

Below are the avaliable commands:

Loadpage

loadpage can be used to load a specific page.

loadpage [page]

History

history is used to manage page history (Backspace equivalent).

history back
history clear

Utility

reload // reloads the page
reload configs // reload config files in ~/.config/youtube-tui/
flush
quit
run [command]
parrun [command]
key [keycode] [keymodifier]
echo [mode] (message) # run youtube-tui help to learn more about modes

The flush command is used to run all tasks in queue immediately, this is usually done automatically.

But for when tasks are stacked up in the same event loop and the order of which they are executed matters, this command can be used to force the already stacked up commands to be ran first.

run is used for running blocking commands, while parrun is non-blocking.

Valid keycodes are the same as in keybindings.yml and commandbindings.yml. For a full list of keys, check out KeyCodeSerde in /src/config/serde.rs.

More about keymodifiers can be found in the doc page for keybindings.yml

Library

bookmark [id]                   Bookmark item with ID (item must be already loaded)
unmark [id]                     Remove bookmark item with ID
togglemark [id]                 Toggle bookmark status
sub/sync [id or url]            Add channel to subscription, or sync an existing channel
unsub [id or url]               Remove channel from subscription
syncall                         Sync all subscriptions

MPV commands

Only with the mpv feature.

mpv prop [label]                Gets mpv property
mpv sprop [label] [value]       Set mpv property
mpv tprop [label] [value]       Toggle a yes/no property
mpv [command]                   Runs a libmpv command

Note that properties and commands are libmpv commands, not mpv commands. Please refer to mpv reference.

Text commands

Text commands generates a text only response without launching the TUI.

help
version

Command bindings

Commands can be binded to keys just like normal key bindings, bindings can be edited in commandbindings.yml. Below are the default bindings:

KeyDescription
Ctrl + FOpen page in browser
Ctrl + CCopy page url
Ctrl + PPlay hovered video
Ctrl + APlay hovered audio
Shift + APlay hovered audio on repeat (shuffled if hovering a playlist)

Config files

Config files are located in ~/.config/youtube-tui, modifying them changes the behavior of the TUI accordingly.

Config files will be generated if not present, backed up and regenerated if there is an issue reading it (most likely caused by changes made by user or updates).

In the following sections we will go through all config files including:

The main config

The main config file is located in ~/.config/youtube-tui/main.yml.

Example main.yml

mouse_support: true
invidious_instance: https://invidious.fdn.fr
write_config: Try
allow_unicode: true
message_bar_default: All good :)
images: Sixels
refresh_after_modifying_search_filters: true
syncing:
  download_images: true
  sync_channel_info: true
  sync_channel_cooldown_secs: 86400
  sync_videos_cooldown_secs: 600
limits:
  watch_history: 50
  search_history: 75
  commands_history: 75
image_index: 4
provider: YouTube
shell: sh
legacy_input_handling: false
env:
  video-player: mpv
  download-path: ~/Downloads/%(title)s-%(id)s.%(ext)s
  terminal-emulator: konsole -e
  youtube-downloader: yt-dlp
  save-path: ~/.local/share/youtube-tui/saved/
  browser: firefox

Below are the description of each of the fields:

mouse_support

Whether mouse click events are supports, if false then mouse will not do anything to the program.

Accept: true/false

invidious_instance

The Invidious instance you want to use, a full list of Invidious instances can be found here here.

Accept: string of a valid url to an Invidious instance

write_config

Whether to write to config after every read, this allows for auto-formatting the config files, as well as removing any error/deprecated options and adding new options.

write_configDescription
MustAlways write to config, panics if failed.
TryTries to write to config, continues if failed.
DontDon't write to config at all

main.yml is a loaded with Try no matter what.

Accept: Must/Try/Dont

allow_unicode

Enable unicode in video and playlist names, doing so may cause unwanted behaviors like video name continuing into the info field to the right.

Accept: true/false

message_bar_default

The default message displayed in the message bar.

Accept: any string

images

How to display thumbnails, if None is selected video thumbnails will not be downloaded in the first place.

Accept: Sixels/HalfBlocks/None

refresh_after_modifying_search_filters

Whether to refresh the current search page after search filters are modified

Accept: true/false

download_images

Whether to download images for all subscription videos

Accept: true/false

sync_channel_info

Whether to also request an updated version of the channel info when syncing feeds. Disabling this halves the number of requests sent to Invidious, but channel info will not be updated (the videos will).

Accept: true/false

sync_channel_cooldown_secs

Sync all do not sync channel info if it has been synced in the past n seconds.

Accept: integer value seconds

sync_videos_cooldown_secs

Sync all do not sync videos from channel if it has been synced in the past n seconds.

Accept: integer value seconds

limits

The maximum length that the watch/search/command history can hold, a value higher will record more items, but will also result in a larger file size in storage.

Accept: positive integer below 2your CPU architecture - 1

image_index

The index in the array of thumbnail qualities you want to download

Typically these are the avaliable qualities:

IndexLabelResolution
0maxres1280 x 720
1maxresdefault1280 x 720
2sddefault640 x 480
3high480 x 360
4medium320 x 180
5default120 x 90
6start120 x 90
7middle120 x 90
8end120 x 90

Usually you don't want to use the max resolution as it will create a large gap between the page being loaded and before the thumbnails are started to get displayed

Accept: integer that is a valid index

provider

This changes the ${url} and ${embed-url} of videos, allowing you to watch videos from Invidious if it is restricted on YouTube.

(Don't always use Invidious if YouTube is working, because first of all the load time if gonna be much slower, and secondly you will be DDoSing Invidious)

Accept: YouTube/Invidious

shell

Shell used to run commands, such as sh (default), bash or even zsh.

Accept: any valid path to a shell binary

legacy_input_handling

Switch back the old key input handling where the selected item captures all input (except escape).

env

Env are variables that can be used in commands.yml, this allows you to change multiple commands by modifying just one env variable. And not to be confused with system/terminal environment variables, these are just "a thing" that you can use in the TUI.

Accept: string_key: string_value pairs

Commands config

The commands config file decides what options (that will run a certain command on select) to be display in the video and playlist page respectively, it is located in ~/.config/youtube-tui/commands.yml.

Example commands config

launch_command: loadpage library ;; flush ;; history clear ;; key Esc 0 ;; key Up 0 ;; key Up 0 ;; key Left 0 ;; key Enter 0 # the key commands select the searchbar on launch
video:
- Reload updated video: run rm '~/.cache/youtube-tui/info/${id}.json' ;; video ${id} # remove the cached info first, then reload the page
- Play video: parrun ${video-player} '${embed-url}'
- Play audio: mpv stop ;; resume ;; mpv sprop loop-file no ;; mpv loadfile '${embed-url}' ;; echo mpv Player started
- Play audio (loop): mpv stop ;; resume ;; mpv sprop loop-file inf ;; mpv loadfile '${embed-url}' ;; echo mpv Player started
- View channel: channel ${channel-id}
- Subscribe to channel: sync ${channel-id}
- Open in browser: parrun ${browser} '${url}'
- Toggle bookmark: togglemark ${id}
- Save video to library: bookmark ${id} ;; run rm -rf '${save-path}${id}.*' ;; parrun ${terminal-emulator} ${youtube-downloader} '${embed-url}' -o '${save-path}%(title)s[%(id)s].%(ext)s'
- Save audio to library: bookmark ${id} ;; parrun rm -rf '${save-path}${id}.*' ;; parrun ${terminal-emulator} ${youtube-downloader} '${embed-url}' -x -o '${save-path}%(title)s[%(id)s].%(ext)s'
- 'Mode: ${provider}': switchprovider

# ...

The few required fields are:

  • video
  • saved_video
  • playlist
  • saved_playlist

Env variables

Notice that a lot of the commands contains the ${label} pattern, this actually replaces the text with the env variables set in main.yml, or is added by the current page (video or playlist) on-the-go.

Env reference

Does not include custom env set in main.yml.

NamePageValue
urlsearch, popular, trending, video, playlistString url to the web page
idvideo, playlistString id of the video or playlist
channel-idvideo, playlistString id of the channel
embed-urlvideoString url to the embed video (required to play video using mpv from Invidious)
all-videosplaylistString urls separated by space to all embed videos in a playlist
hover-urltrending, popular, searchUrl of the currenly hovering item.
hover-channel-urlfeedUrl of the currenly hovering channel.
hover-channel-idfeedID of the currenly hovering channel.
hover-video-urlfeedUrl of the currenly hovering video.
hover-video-idfeedID of the currenly hovering video.
all-idsplaylistIDs of all videos in a playlist, separated with space.
offline-pathSaved video and playlist onlyDirect path to saved file.
mpv-queuelistOnline playlists onlyValid mpv command to queue all videos in the list.
offline-queuelistSaved playlists onlyValid mpv command to queue all saved videos in the list.

Keybindings config

The keybindings config binds each key to an action, or multiple keys for the same action. It can be found in ~/.config/youtube-tui/keybindings.yml.

Example keybindings config

'q':
  0: Exit
Down:
  0: MoveDown
'r':
  2: Reload
Enter:
  0: Select
'l':
  0: MoveRight
Up:
  0: MoveUp
'j':
  0: MoveDown
End:
  0: ClearHistory
Right:
  0: MoveRight
Backspace:
  0: Back
'h':
  0: MoveLeft
F5:
  0: Reload
'k':
  0: MoveUp
Esc:
  0: Deselect
Home:
  0: FirstHistory
Left:
  0: MoveLeft
  4: Back

Keys

Keys can be:

  • A single character (e.g. 'q')
  • Named keys (e.g. Up, Down)
  • Function keys (e.g. F5)

Key modifiers

Key modifiers are the modifier keys that are pressed along with the actual key, for instance in Ctrl + C would have the modifier Ctrl and the key C.

Each modifier has its own code, for instance Shift would be 1 and Ctrl would be 2. The final modifier will be the sum of all modifier keys. (Ctrl + Shift would be a 3).

Keys reference

All possible keys can be found here.

Key actions

All key actions can be found in KeyAction under /src/global/structs/keyaction.rs.

Modifiers reference

ModifierCode
None0
Shift1
Ctrl2
Alt4
Super/"Windows" key8
Hyper16
Meta32

All key modifiers (if any are added) will be in the code.

Command bindings

Commands can be binded to keys (just like normal keybindings), it allows functionalities such as playing hovered videos. Bindings can be either global or page specific, it is located in ~/.config/youtube-tui/commandbindings.yml.

Example commandbindings config

global:
  'f':
    2: run ${browser} '${url}'
  'c':
    2: cp ${url}
video: {}
search:
  'a':
    2: run ${terminal-emulator} mpv '${hover-url}' --no-video
  'A':
    1: run ${terminal-emulator} mpv '${hover-url}' --no-video --loop-playlist=inf --shuffle
  'p':
    2: run mpv '${hover-url}'
watchhistory:
  'A':
    1: run ${terminal-emulator} mpv '${hover-url}' --no-video --loop-playlist=inf --shuffle
  'p':
    2: run mpv '${hover-url}'
  'a':
    2: run ${terminal-emulator} mpv '${hover-url}' --no-video
# etc

Specifications are same as comamnds.yml, the exact same envs can be used.

Default bindings can be found in this section.

Layout config

The layout config determins the position of where each item is placed, mainly their order. The config file can be found in ~/.config/youtube-tui/pages.yml.

Example layout config

main_menu:
  layout:
  - type: NonCenteredRow
    items:
    - SearchBar
    - SearchFilters
  - type: CenteredRow
    items:
    - Popular
    - Trending
    - History
  - type: NonCenteredRow
    items:
    - ItemList
  - type: NonCenteredRow
    items:
    - MessageBar
  message: Loading main menu...
  command: key Esc 0 ;; key Up 0 ;; key Left 0 ;; key Enter 0 # this focuses on the search bar

# and much more ...

Items

Each item is an individual "thing", these things can be optionally selectable, or hoverable by the cursor.

Rows

A row is a horizontal row of items, it can be either centered (like the buttons) or non centered (which will align to the left).

Non centered rows are faster and less crash prone compared to centered rows.

Each item are ordered from left to right.

Message

The message to display when loading the page.

Command

Command to run when the page loads, you can use the key command to select an item on load.

Items reference

ItemCan be used in pageDescription
MessageBarAnyThe panel (default in the bottom of every page) that displays message and error messages
SearchBarAnyA text field that searches that entered query
SearchFiltersAnyA button that brings up a popup for modifying search filters
TrendingAnyLoads the trending page
PopularAnyLoads the popular page
HistoryAnyLoads the watch history page
ItemListMain menu/searchDisplay multiple videos, channels, or playlists in a list
SingleItemInfoSingle itemDisplay info of one single item (a single video or playlist)
ChannelDisplayChannel displayDisplay information of a channel, depending on the page
ChannelMainChannel displayLoads the main channel page
ChannelVideosChannel displayLoads the channel videos page
ChannelPlaylistsChannel displayLoads the channel playlists page
ChannelListFeedDisplays subscribed channels
VideoListFeedDisplays videos of subscribed channels

Appearance config

Appearance config controls the colours and the "looks and feel" of the TUI, it is located in ~/.config/youtube-tui/appearance.yml.

Example appearance config

borders: Rounded
colors:
  text: Reset
  text_special: Reset
  text_secondary: Reset
  text_error: LightRed
  outline: Reset
  outline_selected: LightBlue
  outline_hover: LightRed
  outline_secondary: LightYellow
  message_outline: '#FF7F00'
  message_error_outline: LightRed
  message_success_outline: LightGreen
  item_info:
    tag: Gray
    title: LightBlue
    description: Gray
    author: LightGreen
    viewcount: LightYellow
    length: LightCyan
    published: LightMagenta
    video_count: '#838DFF'
    sub_count: '#65FFBA'
    likes: '#C8FF81'
    genre: '#FF75D7'
    page_turner: Gray

Below are the description of each of the fields:

borders

The style of the borders/outline, if outdated view here.

Accept: Plain/Rounded/Double/Thick

Literally everything else

Any colours, here are the 2 main represenations of colours, for more check out this page here.

Terminal colour

This can be modified by the themes of your terminal (e.g. white, green, etc).

Hex

Hex should be a string that starts with the # character, and can be from 000000 (black) to FFFFFF (white).

RGB color values has been deprecated

Default search options

The default search query/filters when launching the TUI, this can be found in ~/.config/youtube-tui/search.yml, but should not be "customised" like how you would to a config file because it's just a configurable default value.

Example search default value

query: ''
filters:
  sort: Relevance
  date: None
  duration: None
  type: All

Below are the description of each field

query

The default query when you launch the TUI.

Accept: any string

sort

How the search results are sorted.

Accept: Relevance/Rating/Date/Views

date

Restrict videos publish date.

Accept: None, Hour, Day, Week, Month, Year

duration

Restrict videos duration.

Accept: None, Short, Medium, Long

type

Restrict video types

Accept: All, Video, Channel, Playlist

All these options can also be changed in runtime using search filters

Custom commands

Define custom commands. It can be found in ~/.config/youtube-tui/cmdefine.yml.

This is still a work in progress, perhaps in the future scripting will be allowed to control and interact with elements within the TUI.

print: echo
pause: mpv sprop pause yes ;; echo mpv Player paused
next: mpv playlist-next ;; echo mpv Skipped
resume: mpv sprop pause no ;; echo mpv Player resumed
search: loadpage search
rc: reload configs

General format:

new command: original command

This allows for alternative shorthand commands.

More about commands run youtube-tui help or check out commands.

Try not to use self referencing commands, it'll make a mess.

Key remaps

Very old concept of hard remapping one key to another. The config file can be found in ~/.config/youtube-tui/remaps.yml.

Not recommended using unless you got some issues that prevents certain keys from being pressed.

How it works

This sections talks about roughly how this TUI works, crates, important structs and their location, and the main event loop will be mentioned.

Table of contents

  • Framework talks about how a single frame is rendered, and how a single input is handled.

Framework

At the core of this TUI, is the framework from the tui-additions crate, it allows the program to render onto the screen, take inputs (mouse and keyboard) in an orderly fashion.

A Framework holds a bunch of other structs, a simplified version would looks something like this.

struct Framework {
	state: Vec<Vec<Item>>,
	cursor: CursorState,
	selectables: Vec<Vec<(usize, usize)>>,
	data: FrameworkData,
	history: FrameworkHistory,
}

State

Holds a 2D array of items, but that is just the simplified version.

The State struct also holds the width of the items, heigh of the rows, and other details such as if the row should be centered or not.

Cursor

The cursor can be in one of these states.

  • Selected - where an item is selected.
  • Hover - when its being moved around.
  • None - when the page first loads, the cursor does not have a state.

Selectables

This is an interesting one. As mentioned below, some items can be hovered when other cannot. Each selectables[x][y] maps to a selectable (hoverable) coordinate.

Instead of using a HashMap<(usize, usize)>, using a 2D array ensures that all x: 0..range and y: 0..range are mapped to a selectable item. And moving the cursor left is as easy as increasing x by 1, without having to worry about selectability check and stuff.

Data

There are 2 pools of data available - global and state.

Global data are global across all pages, this is mainly used to store config structs, as they are meant to be applied globally.

State data are exclusive to each page, this is done to ensure that each page will get the correct data.

For example, if state data is not used, the next page will overwrite data in the previous page, making going back in history impossible.

This showed how state data stays with the history snapshot of the page, whereas global data does not.

History

This stores the past states and data of the struct, pretty self explanatory.


Items

Items are placed across the screen in rows, each item is individual and changing of one should not affect others in anyway.

Diagram showing that individual items arranged in rows on screen.

Each item has a set of functions from the trait FrameworkItem:

.selectable(&self) -> bool

The function is ran on page load, it determines whether the item can be hovered by cursor or not.

Most item returns true, as they can be selected and hovered.

However there are some exceptions, including MessageBar and the big info display in channel home page.

PageButtons returns true in this function, as they can be hovered by cursor. Instead, .select() is responsible for their special behaviour.

.select(&mut self, &mut Framework) -> bool

This function is ran when an item is selected (pressed enter on), it allows the item to modify its own state and the framework state. The returned boolean also determines if the selecting item will stay selected and capture key input.

Most items returns true in this function, for example SearchBar stays selected and captures key input after being selected, until deselect.

PageButtons returns false, as they don't want to say selected. This does not mean the function does nothing, they are still able to modify their own states and push a LoadPage task to queue.

.deselect(&mut self, &mut Framework) -> bool

This function is the exact opposite of the .select() function, it is called when the deselect keybinding (Esc) is pressed, or the mouse clicks somewhere outside the item.

All items returns true on this function.

A fun fact is that items can actually return false, and refuse to get deselected. This can be useful when waiting for a condition to be met.

.load_item(&mut self, &mut Framework, ...) -> Result

This is the function responsible for the loading of items. The YouTube TUI adds an empty item to the screen, then calls this function for the item to load itself.

An item that heavily rely on this function is ItemList, it loads video according to the current page, whether it's Library, History or Search.

Currently, this function can be very inefficient as items are loaded one after another (sync). This will improve once Rust implements async traits.

Errors will be displayed in MessageBar in the next frame.

.render(&mut self, &mut Framework, &mut Frame, area)

Items should be able to render itself within area of Frame, the area is different for each item, and should not overlap.

Each frame is rendered 2 times.

  1. Render all normal items.
  2. Render all popups, as they need to be above normal items.

Normal items should not render in the popup render, for example:

if popup_render {
	return;
}

.key_event(&mut self, &mut Framework, KeyEvent) -> Result

Pretty self explanatory, selected item takes in a key event and do some modification to itself and/or the Framework state.

Errors will be displayed in MessageBar in the next frame.

.mouse_event(&mut self, &mut Framework, x, y) -> bool

Similar to key_event, this function takes in the relative x and y of the mouse click on the item.

The return boolean indicates if the item has been modified by the mouse click, if true then the screen will rerender.

Event loop

The event loop is like the glue that puts everything together.

Before the event loop

But before the TUI enters it's main event loop, it does several things.

1. Check what command is being ran.

If the command does not need to enter the main TUI, don't enter the main TUI.

For example, help or version just returns a text message on your terminal screen. In main.rs line 19, it is checked whether the entered command is a valid text command. If so, the program exits without ever reaching the TUI code.

2. Enable raw mode

If you've tried killing youtube-tui while it's running (killall youtube-tui), your terminal should be in a weird state - where everything, including mouse movement seem to be captured. That's the raw mode.

I have no idea what is special about it, but it is in the examples of tui-rs here (one of the main dependency of this TUI).

3. Init

There are a bunch of things happening in this stage, but it really just boils down to a few basic things:

  • Reading/creating config files, subscriptions, libraries and inserting them to the pool of shared data (global data) within the framework struct.

Global data is used here, the reason should be obvious. All pages, should share the same config, there is no need to keep extra copies of the (usually) same thing and waste memory.

  • Insert some structs needed for the TUI to run.

These structs includes Message storing the message to be displayed in message bar, and Status, useful for storing all sorts of values, for example helping with the running (mostly rendering) of the TUI.

  • Move some files

Some files have to be moved to ~/.cache/youtube-tui/ from (usually) ~/.local/share/youtube-tui/ for stored content to be used by the TUI, this is why running multiple instances of the program can mess things up - as one instance exits the files got moved from .cache to .local, and the other instance no longer sees the files they thought was still in .cache.

The full init code is here


todo...

Changelogs

v0.8.0 (latest)

Added

  • Built in MPV player, controlled by command mpv [libmpv command] [args...]
  • Command/search histories.
  • Keys remapping, custom commands.

Fixed

  • Some keys captured in search bar and are not working #37.

v0.7.4

Added

  • Ctrl + w and Ctrl + u in search bar and command mode.
  • Keybindings works even when an item is selected (legacy_input_handling: false in main.yml).
  • Creating fake key input using :key

Fixed

  • Search filters popup closing when you click on it.
  • Configured keybindings in all items.
  • Fixed multiple issues in #35

v0.7.3

Added

  • Lazy feed syncing (configurable), so you are not actively ddosing the Invidious instance as badly.

Fixed

  • Search bar no longer shows escaped search query: the original text string is displayed instead.
  • Fixed something about labeling channels with * although no new video is published.
  • Blank screen on loadpage if itemlist is empty.

v0.7.2

Added

  • Feeds page, and the subscriptions system.
  • Reduced compile time needed by a lot.

Fixed

  • Search url not escaped, so searches with symbols or spaces are now working.

v0.7.1

Added

  • Options for config loading. (write_config in main.yml)
  • Parrallel/blocking commands parrun/run

Fixed

  • Fixed crashing when launching without permissions to write to config files (issue 29)

v0.7.0

Added

  • File system based caching
  • Bookmark library
  • Save video/playlists for offline viewing

Fixed


v0.6.2

Added

  • Command bindings

Fixed

  • Image not cleared when going back to "switch view"

v0.6.1

Added

  • Rework of the env system, now using environment variables provided by the OS as opposed to implmenting own version of env
  • Ability to use envs in command mode
  • Launch commands (including youtube-tui help)

Fixed

  • Screen blinking when pressing up arrow on the first item in playlist page, videos view

v0.6.0

Added

  • Mouse support
  • Vim-like commands
  • Pasting with Ctrl + V in search bar and command mode

v0.5.3

Fixed

  • Search bar could not handle non English characters (e.g. Russian)

v0.5.2

Added

  • Improved config files (including hex colour support)
  • Page turners (next/prev page in search)

Fixed

  • Where the image and text are displaying in the same place, and the image is displayed over the text

v0.5.1

Added

  • Image lazy loading (will not rerender image if already rendered)
  • Optional features that can be disabled

v0.5.0

Added

  • Entire TUI rewritten from scratch, now using the tui-additions crate
  • Sixels image support
  • Improved config files

v0.4.4

Added

  • Added default select item for each page (can be changed in layouts.yml)

Fixes

  • Video list view in playlists not working
  • Channel view scroll causes panic
  • Search options gray backgound + image covering popup

v0.4.3

Added

  • Refreshing page
  • Key modifiers for key bindings
  • Image loading can be disabled

Fixes

  • Fixed cache not being cleared after exit

Contributors

Siriusmart

Creator and main developer of YouTube TUI.

LuckyTurtleDev

Maintainer of the youtube-tui package on AUR.

Ruixi-rebirth

Maintainer of the youtube-tui on the NixOS repository.

Zaedus

Maintainer of the youtube-tui-full-bin, youtube-tui-nodefaults-bin and youtube-tui-git package on AUR.

Fractal Tess, msrd0

Fixed typos in README.