YTFZF(5)

πŸ“¦
version 2.6.2 Β· 3 versions
, in alpine 3.24, arch rolling, nixos 26.05, nixpkgs unstable

πŸ’– YTFZF(5) β€” the ytfzf config file, bestie πŸ’–

🌸 NAME 🌸

ytfzf β€” the configuration file for ytfzf. That's the whole name section, iconic.

✨ SYNOPSIS ✨

~/.config/ytfzf/conf.sh

πŸ’… DESCRIPTION πŸ’…

Okay so the configuration file is a .sh file and can be used as such. No cap.

The file can be completely empty and ytfzf will still work with the default settings. Literally empty. Zero notes. It still slays.

The options should be set as environment variables and functions.

πŸ—‚οΈ CONFIGURATION FILES πŸ—‚οΈ

Configuration files are stored in $XDG_CONFIG_HOME/ytfzf (or $HOME/.config/ytfzf).

conf.sh

A shell script that gets sourced into ytfzf when ytfzf is run.

subscriptions

A file that is a list of links to youtube channel's video page, such as:

https://www.youtube.com/channel/UCtMVHI3AJD4Qk4hcbZnI9ZQ

Each link should be separated by a new line.

If a channel appears similar to "https://www.youtube.com/c/SomeOrdinaryGamers", run ytfzf --channel-link="https://www.youtube.com/c/SomeOrdinaryGamers" Before adding it to your subscriptions file.

A comment can be created by having #comment on its own line or after a link. For example:

link-to-channel
#comment
link-to-channel #best channel

scrapers

A folder that contains executable files that scrape websites. See CUSTOM SCRAPERS for more information.

🧠 CONFIGURATION OPTIONS 🧠

πŸ—‚οΈ VARIABLES πŸ—‚οΈ

conf.sh is used mainly for setting variables for ytfzf. If a variable has no default, that means it is set to an empty string.

To set a variable in conf.sh, be sure to use:

variable_name="value"

leave out the $ at the start of the variable name. Yes, bestie, no dollar sign at the front. πŸ’…

πŸ“ Files and directories

  • $cache_dir β€” The directory to store cache files in. It is highly recommended to only change this if $__is_submenu is 0, or funky things could happen. default: $XDG_CACHE_HOME/ytfzf (or $HOME/.cache/ytfzf)
  • $hist_file β€” The file to write watch history to if $enable_hist is 1. It is highly recommended to only change this if $__is_submenu is 0, or funky things could happen. default: $cache_dir/watch_hist
  • $search_hist_file β€” The file to write search history to if $enable_search_hist is 1. default: $cache_dir/search_hist

🎬 How to play the selected videos.

  • $is_detach β€” Whether or not to detach the video player from the terminal. default: 0
  • $is_audio_only β€” Whether or not to only play audio. default: 0
  • $url_handler β€” The function/programs to handle the selected videos. It is recommended to not set this variable directly, but rather to use the command load_url_handler. See URL handlers for a list of built-in url handlers. default: multimedia_player
  • $yt_video_link_domain β€” The domain to play youtube videos from (does not apply to odysee and peertube or youtube playlists). If left blank, the value will be whatever invidious instance ytfzf chose. default: https://www.youtube.com
  • $info_to_print β€” The information to print instead of playing a video. The available options for this variable are:
    • L | l | link β€” Print the URL of the selected videos.
    • VJ | vj | video-json β€” Prints the json of the selected videos.
    • J | j | json β€” Prints the json of all the videos in the search results.
    • F | f | format β€” Prints the video format being used.
    • R | r | raw β€” Prints the data of the selected videos, as appears in the menu.
  • $info_wait_action β€” The action to do when $info_wait is 1. Valid actions:
    • q β€” quit (will go back to menu, if $is_loop is 1).
    • Q β€” quit regardless if loop is enabled or not.
    • m β€” return to menu. default: q
  • $info_wait β€” Whether or not to wait for input after printing info. default: 0
  • $video_pref β€” The video preference to use for youtube-dl in mpv. default: bestvideo
  • $audio_pref β€” The audio preference to use for youtube-dl in mpv. default: bestaudio
  • $ytdl_pref β€” The preference to use for youtube-dl in mpv. default: $video_pref+$audio_pref/best/$video_pref/$audio_pref
  • $url_handler_opts β€” Opts to pass to the url handler. By default this will pass extra opts to mpv. This can also be set in the config file with url_handler_opts.
  • $interface β€” The interface/menu to use. It is recommended to not use this variable directly, instead use load_interface interface-name. Valid options:
    • ext β€” same as -D
    • scripting β€” is applied when -a, -r, or -A is used
    • '' β€” default
  • $external_menu_len β€” The amount of cols in interface_ext, (-D). default: 210
  • $fzf_preview_side β€” The side to show the preview in fzf. Valid options:
    • left
    • right
    • up
    • down default: left
  • $preview_window_width β€” The amount of space to use for the fzf preview. default: 50%
  • $thumbnail_viewer β€” The program to display images for thumbnail previews. It is recommended to not use this variable directly, instead use load_thumbnail_viewer viewer. Valid options:
    • sixel
    • iterm2
    • kitty
    • sway
    • wayland
    • ueberzug
    • chafa
    • chafa-16 β€” Uses chafa with 16 colors
    • chafa-tty β€” Uses chafa with 4 colors
    • catimg
    • catimg-256 β€” Uses catimg with 256 colors
    • mpv β€” Uses the mpv player to display the images. Works well with tiling window managers.
    • imv β€” Similar to mpv, but is a dedicated image viewer
    • swayimg β€” Only works on the sway wayland compositor
    • swayimg-hyprland β€” Only works on the hyprland compositor. Uses swayimg to render images. default: ueberzug
  • $show_formats β€” Whether or not to bring up the format selection menu. default: 0
  • $format_selection_screen β€” The format that selection screen will use. Types: simple, normal. default: simple
  • $format_selection_sort β€” The --format-sort to use in ytdl. default: height
  • $enable_submenus β€” Whether or not to enable submenus. A submenu is a menu that appears after a playlist or channel is selected. (Currently only supported with youtube/invidious scraper) default: 1
  • $enable_actions β€” Whether or not to enable actions such as submenus, and the back button. default: 1
  • $keep_vars β€” Whether or not options passed into ytfzf also get passed into submenus.
  • $enable_back_button β€” Whether or not to enable back button in submenus. default: 1
  • $submenu_opts β€” Options to use in submenus. default: (empty)
  • $submenu_scraping_opts β€” DEPRECATED (use submenu_opts instead). Does the same thing as $submenu_opts. default: (empty)
  • $is_sort β€” Whether or not to sort scraped videos by date in the menu. default: 0
  • $fancy_subs β€” Whether or not to have a separator between each subscription. default: 0
  • $fancy_subs_left β€” The text to display on the left of the channel name when fancy_subs is 1. default: -------------
  • $fancy_subs_right β€” The text to display on the right of the channel name when fancy_subs is 1. default: $fancy_subs_left
  • $show_thumbnails β€” Whether or not to show thumbnails in fzf. default: 0
    • $async_thumbnails β€” Whether or not to download thumbnails asynchronously. Downloading asynchronously will open the menu before all thumbnails are downloaded. default: 0
  • $skip_thumb_download β€” Whether or not to skip thumbnail download. default: 0
  • $thumbnail_quality β€” Select the quality of the thumbnails. Currently only supports youtube (uses invidious api). This does not work for the -cS scraper as it scrapes youtube not invidious (use SI instead). For lower internet speeds it is recommended to use default. Available options:
    • maxres
    • maxresdefault
    • sddefault
    • high β€” (default)
    • medium
    • default
    • start β€” The first frame of the video (low quality)
    • middle β€” The middle frame of the video (low quality)
    • end β€” The end frame of the video (low quality)
  • $notify_playing β€” Whether or not to send a notification when a video is about to be played. default: 0
  • $is_loop β€” Whether or not to show the menu after the selected videos have stopped playing. default: 0
  • $search_again β€” Whether or not to make another search after fzf is closed. default: 0
  • $selection_meta_key β€” The meta key for shortcuts that select a video. default: alt
  • $download_shortcut β€” the key combo for downloading the selected vids πŸ’Ύ. default: $selection_meta_key-d
  • $video_shortcut β€” the one for watching the selected vids 🎬. default: $selection_meta_key-v
  • $audio_shortcut β€” for listening to the selected vids 🎧. default: $selection_meta_key-m
  • $detach_shortcut β€” the shortcut that uses the detach player 🫑. default: $selection_meta_key-e
  • $print_link_shortcut β€” use this to print the link πŸ”—. default: $selection_meta_key-l
  • $show_formats_shortcut β€” shows formats before playing the video πŸ“Š. default: $selection_meta_key-f
  • $info_shortcut β€” gets ALL the info about the selected video πŸ”. default: $selection_meta_key-i
  • $search_again_shortcut β€” makes another search, bc bestie we can do better πŸ”. default: $selection_meta_key-s
  • $action_meta_key β€” the meta key for shortcuts that actually do something ⚑. default: ctrl
  • next_page_action_shortcut β€” scrapes the next page πŸ“„. default: $action_meta_key-p
  • $shortcut_binds β€” literally the keys fzf listens for πŸ‘‚. default: Enter,double-click,$download_shortcut, $video_shortcut,$detach_shortcut,$print_link_shortcut,$show_formats_shortcut, $info_shortcut,$search_again_shortcut,$custom_shortcut_binds"
  • $custom_shortcut_binds β€” your custom shortcut keys 🎯. automatically appended to $shortcut_binds. > if you set $shortcut_binds manually, you gotta manually append this too, no cap.

🎯 Auto selecting

  • $is_auto_select β€” auto selects the first -n videos (only works if $interface=scripting). default: 0
  • $is_random_select β€” randomly selects -n videos (only works if $interface=scripting). default: 0
  • $is_specific_select β€” selects a specific video (use $ scripting_video_count to pick which, only works if $interface=scripting). default: 0
  • $scripting_video_count β€” how many videos to grab with -a or -r. default: 1

πŸ•·οΈ Scrapers

  • $scrape β€” the site to scrape by default. the currently supported options are literally:
    • youtube,
    • youtube-trending,
    • youtube-subscriptions,
    • peertube,
    • odysee/lbry.
    • youtube-playlist,
    • youtube-channel,
    • invidious-channel,
    • video-recommended,
    • playlist/json-file,
      • the search will be a path to a json file laid out as described in VIDEO JSON FORMAT
    • history,
    • url/U,
    • u,
    • M/multi,
    • comments default: youtube
  • $multi_search β€” enables multi search πŸ„. default: 0
  • $search_sort_by β€” the attribute to sort by when searching πŸ“ˆ:
    • relevance (default)
    • rating (youtube only)
    • upload_date
    • oldest_first (odysee only)
    • view_count (youtube only)
  • $search_upload_date β€” search for vids within the last πŸ•:
    • hour
    • today
    • week
    • month
    • year
  • $search_video_duration β€” search for long or short vids. possible options:
    • short
    • long
  • $search_result_type β€” the type of results you get 🎁:
    • video (default)
    • playlist
    • channel
    • all (may not work on some instances, fair warning πŸ’€)
  • $nsfw β€” searches for nsfw videos in odysee/O πŸ™ˆ. default: false
  • $search_result_features β€” the features a video should have (comma separated) βœ…:
    • hd
    • subtitles
    • creative_commons
    • 3d
    • live
    • 4k
    • 360
    • location
    • hdr
  • $search_region β€” the region (country code) to search 🌍. default: US
  • $invidious_instance β€” the invidious instance to use 🌐. default: https://vid.puffyan.us
  • $pages_to_scrape β€” how many pages to scrape on youtube/invidious πŸ“š. default: 1
  • $pages_start β€” the starting page to scrape 🏁. default: 1
  • $max_thread_count β€” how many threads can be used while scraping youtube search, playlists, and channels 🧡 (this does NOT apply to the subscription scraper). default: 20
  • $odysee_video_search_count β€” how many videos to scrape on odysee πŸ“Ό. default: 30
  • $sub_link_count β€” how many videos to scrape per channel when getting subscriptions πŸ“Ί. default: 2

πŸ§ƒ Misc

  • $gap_space β€” the amount of space after the title in the thumbnail viewer menu πŸ“. default:' '
  • $scrape_search_exclude β€” the scrapers to NOT ask for a search query πŸ™…β€β™€οΈ. > bestie be sure to have a space at the end AND beginning of the string. default: youtube-subscriptions S SI T youtube-trending H history
  • $custom_scrape_search_exclude β€” extra scrapers that skip the search query 🚫. this auto-appends to $ scrape_search_exclude. plus you don't need spaces at the start and end, only between scrapers. default:
  • $gap_space β€” a number of spaces equal to half the width of your terminal πŸ“. default: 115 spaces
  • $enable_hist β€” keep track of history or nah πŸ—‚οΈ. default: 1
  • $enable_search_hist β€” keep track of search history or nah πŸ”Ž. default: 1
  • $search_source β€” how to get the search query. the builtin values are:
    • args β€” use commandline arguments as the search (default)
    • prompt β€” ask for a search via a prompt
    • hist β€” use search history.
    • next β€” used internally to use the next search in the list when multi_search is enabled.
    • fn-args β€” used internally to use the function arguments passed to the function as the source.
  • $log_level β€” how much debug info to log πŸͺ΅:
    • 2 β€” log everything
    • 1 β€” log only warnings and errors
    • 0 β€” log only errors default: 2
  • $thumbnail_debug_log β€” the log file for thumbnail debug info πŸ–ΌοΈ. default:/dev/null
  • $useragent β€” the useragent used when scraping websites πŸ•΅οΈβ€β™€οΈ. default: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.152 Safari/537.36"
  • $ytdl_opts β€” the command-line options passed to youtube-dl when downloading βš™οΈ.
  • $ytdl_path β€” path to youtube-dl or a fork of youtube-dl for downloading πŸ› οΈ. > if yt-dlp is installed that gets preferred over youtube-dl. default: youtube-dl

πŸ”§ Option Parsing

  • $long_opt_char β€” the char to use for long opts βž–. default: -
  • $optstring β€” the string of options for the getopts function 🧩. > highly unrecommended to change this variable, unless you actually know what you're doing. default: ac:de:fhi:lmn:qrstu:xADHI:LS:T:W:$long_opt_char:
  • $YTFZF_CHECK_VARS_EXISTS β€” whether to check if variables in the environment already exist when setting default options πŸ”Ž. > this one can NOT be set in the config, it has to be set in your startup shell with export, or before running ytfzf like: YTFZF_CHECK_VARS_EXISTS=0 ytfzf ... default: 1

πŸ—ƒοΈ State

State values are NOT meant to be modified by the user. like, hands off bestie πŸ’…
  • $__is_submenu β€” whether the script is in a submenu.
  • $__is_fzf_preview β€” whether the script is running to display an fzf preview.
  • __scrape_count β€” the current scrape count starting at 1.

πŸ› οΈ FUNCTIONS

sometimes a variable just isn't good enough, and instead functions should be defined 🫢. to find the default value of these, check the source code by searching for function_exists "<function_you_are_looking_for>".

  • external_menu() β€” when $interface is ext_menu, call this function instead of fzf. takes 1 argument, a prompt string.
  • get_sort_by() β€” called to get the value to sort by when $is_sort is 1. takes in a line in the form of "title |channel |duration |views |date |id".
  • data_sort_fn() β€” sorts the data being piped into it πŸ“Š. takes no arguments, all data is piped into it.
  • custom_info_wait_action_<text>() β€” called if an unknown $info_wait_action is given or read. <text> should be replaced with the text wanted from $info_wait_action, eg: custom_info_wait_e. takes no arguments.

video_info_text()

This lil cutie prints the text for the selection menu ✨ Two rules and you cannot break them: it must end with a new line, and the url has to be the last thing printed. Like, actually last. The very last. No cap πŸ’…

Takes no arguments β€” the spicy variables just hang out in the environment:

  • title
  • channel
  • duration
  • views
  • date
  • url

Lowkey recommended that you go read the script itself to see exactly how each thing gets printed. iykyk 🫢

thumbnail_video_info_text()

This one prints the text in the preview area of fzf when thumbnails are enabled πŸŽ€ Print literally whatever you want, however you like β€” this is your canvas, bestie, go off.

No arguments here either, and the relevant variables are:

  • title
  • channel
  • duration
  • views
  • date
  • url

thumbnail_video_info_text_<scraper>()

Same exact energy as thumbnail_video_info_text(), just scoped to a specific scraper. The <scraper> part is whatever scraper you're targeting, slay πŸ¦‹

on_no_thumbnail()

This function gets run when no thumbnail is found 😭 (the sad path, but somebody's gotta handle it).

get_ueberzug_positioning_left()

This function sets the variables $width, $height, $x, and $y. Important vibe check: $x and $y represent cols and lines, not pixels, okay? πŸŽ€

These variables are what position and size the image in the fzf preview when $fzf_preview_side is left.

It takes 2 arguments:

  • max_width
  • max_height

get_ueberzug_positioning_right()

Sets the variables $width, $height, $x, and $y. And again β€” $x and $y are cols and lines, not pixels, bestie πŸ’…

These variables position and size the image in the fzf preview when $fzf_preview_side is right.

Takes 2 arguments:

  • max_width
  • max_height

get_ueberzug_positioning_up()

Sets the variables $width, $height, $x, and $y. Same deal as always: $x and $y are cols and lines, not pixels ✨

These get used to position and size the image in the fzf preview when $fzf_preview_side is up.

Takes 2 arguments:

  • max_width
  • max_height

get_ueberzug_positioning_down()

Sets the variables $width, $height, $x, and $y. You already know the drill: $x and $y = cols and lines, never pixels 🫢

These are what position and size the image in the fzf preview when $fzf_preview_side is down.

Takes 2 arguments:

  • max_width
  • max_height

get_swayimg_positioning_left()

Here's where it switches up πŸ”₯ This one sets the variables $x, $y, $img_w, and $img_h. $x and $y should represent pixels β€” yes, this time it's pixels, don't get it twisted.

These variables get used to position and size the image in the fzf preview when $fzf_preview_side is left.

It takes 8 arguments:

  • img_w
  • img_h
  • max_width
  • max_height
  • max_height
  • term_x
  • term_y
  • col_px_width
  • line_px_height

get_swayimg_positioning_right()

Sets the variables $x, $y, $img_w, and $img_h β€” and $x and $y are in pixels, periodt πŸ’…

Used to position and size the image in the fzf preview when $fzf_preview_side is right.

Takes 8 arguments:

  • img_w
  • img_h
  • max_width
  • max_height
  • max_height
  • term_x
  • term_y
  • col_px_width
  • line_px_height

get_swayimg_positioning_up()

Sets the variables $x, $y, $img_w, and $img_h. Pixels for $x and $y, bestie, always pixels 🌸

These position and size the image in the fzf preview when $fzf_preview_side is up.

Takes 8 arguments:

  • img_w
  • img_h
  • max_width
  • max_height
  • max_height
  • term_x
  • term_y
  • col_px_width
  • line_px_height

get_swayimg_positioning_down()

Sets the variables $x, $y, $img_w, and $img_h, with $x and $y in pixels ⭐

Positioning and sizing for the image in the fzf preview when $fzf_preview_side is down.

Takes 8 arguments:

  • img_w
  • img_h
  • max_width
  • max_height
  • max_height
  • term_x
  • term_y
  • col_px_width
  • line_px_height

search_prompt_menu()

This one asks the user to make a search query and then sets the variable $_search to that query πŸ”

It's called when ytfzf is started without a search (and it's using the default interface).

Takes no arguments. Iconic, honestly.

search_prompt_ext()

Same thing: asks the user to make a search query and sets $_search to the query.

Called when ytfzf starts without a search (and it's using the -D flag).

Takes no arguments.

quick_menu()

This function should take user input and echo it back πŸŽ€

It's called with -f and -q, or any other time a generic menu is needed (and the default interface is being used).

It takes 1 argument and takes input from stdin:

  1. The prompt to use.
  • stdin: the items to choose from (separated by new lines)

quick_menu_ext()

Should do the exact same thing as quick_menu() πŸ’…

Called when quick_menu() would be called, but when -D is enabled.

It takes 1 argument and takes input from stdin:

  1. The prompt to use.
  • stdin: the items to choose from (separated by new lines)

info_wait_prompt()

This is the prompt to use when info_wait is enabled. Takes no arguments ✨

info_wait_prompt_ext()

Same as info_wait_prompt() when -D is used. Takes no arguments.

info_wait_prompt_wrapper()

Calls info_wait_prompt_<interface_name> πŸ¦‹ Takes no arguments.

display_text()

Prints text to standard out. Takes an unlimited number of arguments to print β€” go wild, throw as many as you want at it πŸ‘‘

display_text_ext()

Prints text to standard out. Also takes an unlimited number of arguments to print.

display_text_wrapper()

Calls display_text_<interface_name>. Takes an unlimited number of arguments to print 🌈


URL handlers

A URL handler is a function that handles the urls that get given to it πŸ’–

URL handlers should take into account these modifier values:

  • $video_pref
  • $is_audio_only
  • $is_detach

Modifier variables get piped into a URL handler, which is the whole reason you can write URL handlers in any language, bestie, it's giving multilingual queen 🌍✨ They get piped in the order shown above, separated by spaces.

multimedia_player()

The handler that's called by default. It opens either video_player() or audio_player(), depending on whether $is_audio_only (-m) is enabled or not πŸ‘€

Takes an unlimited amount of arguments, each of which is a link to a video.

video_player()

Plays the urls with a video player. Takes an unlimited amount of arguments, each of which is a link to a video 🎬

audio_player()

Plays the urls with an audio player. Takes an unlimited amount of arguments, each of which is a link to a video 🎧

downloader()

Downloads the urls. Takes an unlimited amount of arguments, each of which is a link to a video πŸ’Ύ

get_video_format_<name>()

A custom format selection screen πŸŽ€

<name> should be the wanted value of $format_selection_screen.

This function should set ytdl_pref.

It takes all urls as separate arguments.

on_open_url_handler_<ext>()

This function runs when open_url_handler is called, but before the url handler is actually opened 🫢

Takes an unlimited number of arguments, and each argument is a url that was opened.

close_url_handler_<name>

<name> should be the name of the url handler with - replaced with _.

A function that happens after the url handler has finished playing. The whole point of this one is to clean up anything the url handler did 🧹✨

after_close_url_handler_<ext>

A function that happens after the url handler has finished playing, and after close_url_handler_<name> has happened.

Heads up though: if is_detach is 1, this function may be called immediately after url_handler opens. So don't be surprised πŸ‘€


Search History

handle_search_history()

This function handles appending the search to the given search file πŸ“

It takes 2 arguments:

  1. The search to write
  2. The file to append to.

parse_search_hist_file()

This function should parse the search history file and print out each search separated by new lines πŸ’…

The search history file gets fed through stdin.

get_search_from_<src>()

If search_source is set to <src>, this function gets called ✨

It's expected to set the variable _search to a search query.

Takes no arguments.

on_search() β€” bestie, this one's your little welcome committee 🫢 it fires every single time a website gets scraped. It eats 2 arguments:

  1. The search query
  2. The current scrape

on_search_<search_query>() β€” same energy as above, except it only fires when the current search matches <search_query>. Very ✨ picky ✨, very targeted. It takes 1 argument:

  1. The current scrape

Misc πŸŽ€

get_requested_info_<name>() β€” if <name> lives inside info_to_print, this function gets run. No arguments, she just vibes and delivers πŸ’…

handle_playing_notifications() β€” this one's the hype squad: it sends a notification for the videos that are about to be played πŸ”₯ It takes an unknown amount of urls as arguments (so like, a lot possible, no cap).

post_scrape() β€” happens after all scraping is complete. The afterparty πŸŽ‰

post_scrape_<extension-name>() β€” same as post_scrape() but for each extension πŸ¦‹

on_opt_parse() β€” this one gets called after an option is parsed, and it sets variables based on the options passed into it. Heads up: a non 0 exit code will override the default behavior of a specific option. She takes 4 arguments:

  1. The current option being parsed
  2. The current option argument being parsed
  3. The unmodified option being parsed. For an option such as -a, this value will be the same as $1. However, for every --long-option this value will be "-".
  4. The unmodified option argument being parsed. For an option such as -c S, this value will be the same as $2. However, for every --long-option=value, this value will be -long-option=value.

on_opt_parse_<opt_name>() β€” gets called before an option is parsed (yes, before β€” she's early, she's punctual ⏰). A non 0 exit code will override the default behavior of a specific option. She takes 3 arguments:

  1. The optarg
  2. The raw opt
  3. The raw optarg

on_post_set_vars() β€” called after all vars are set and all opts are parsed. The "okay everyone's seated, let's go" moment πŸ’œ Takes no arguments.

on_clean_up() β€” called when the script is cleaning up files from the search, or when the script exits. She's the friend who tidies up before leaving the party 🧹 Takes no arguments.

usage() β€” calls the print_help_<ext> for each loaded extension πŸ“– Takes no arguments.

handle_custom_keypresses() β€” called inside the internal handle_keypress() function. This function should return 0 to not override the default handle_keypress() function. It takes 1 argument:

  1. The key pressed

handle_custom_post_keypresses() β€” called inside the internal handle_post_keypress() function; it should return 0 to not override the default handle_post_keypress() function. Its whole job is to undo the changes of the last keypress (the "jk, go back" function πŸ™ˆ). It takes no arguments β€” it must get the keypress from $keypress_file.

handle_keypress_*() β€” replace the * with the name of the shortcut, eg: alt_d, and also replace any - with _. This function is called after handle_custom_keypresses() if it returned 0, and the shortcut is not a built-in shortcut. Takes 0 arguments.

handle_post_keypress_*() β€” same naming rules: swap * for the shortcut name, eg: alt_d, and replace any - with _. This one gets called after handle_custom_post_keypresses() if it returned 0, and the shortcut is not a built-in shortcut. Takes 0 arguments.

handle_custom_action() β€” called when an unknown action (as described in VIDEO JSON FORMAT) is given. It takes 1 argument:

  • The action.

Exit codes, listen up πŸ‘‘:

  1. go back to menu
  2. exit

πŸŽ€ CUSTOM THUMBNAILS πŸŽ€

Custom thumbnails live in $YTFZF_CUSTOM_THUMBNAILS_DIR. The name of the image must be <video-id>.jpg β€” no exceptions, that's the whole contract πŸ’…

Wanna see an example? Make a search with ytfzf and locate the thumbnails folder in $cache_dir/search ✨

Custom thumbnails are going to try to be loaded before the official thumbnail. And if a custom thumbnail exists but the official thumbnail doesn't, ytfzf will try to use $YTFZF_CUSTOM_THUMBNAILS_DIR/YTFZF:DEFAULT.jpg as the fallback 🫢


🌈 VIDEO JSON FORMAT 🌈

This is the format used for playlists and custom scrapers. Videos should be objects in a list β€” like a little friend group of dicts πŸ¦‹

Required object keys:

  • ID (string): a unique id to the video
  • url (string): the url to the video
  • title (string): the title of the video
  • scraper (string): The scraper that created the json (used for thumbnails)
    • thumbs (string): a url to a thumbnail/image
    • channel (string): the channel name
    • duration (string): length of the video (standard: [HH:]MM:SS)
    • views (string): amount of views a video has
    • date (string): upload date (standard: date is relative to current day, eg: 3 days ago)
    • action (string): an action in the format of "action [key=value key2=value2...]"

Example JSON, literally copy-paste ready 😭:

[
    {
     "ID": "dQw4w9WgXcQ",
     "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
     "title": "definitely not never gonna give you up"
    }
]

πŸ’– PLAYLISTS πŸ’–

A playlist is a json file in the format of VIDEO JSON FORMAT. Easy. To easily get the formatted json for a video, just run:

ytfzf -I VJ <search

That's it, that's the trick 🀫


⭐ SORT NAMES ⭐

A sort name is a function in your config file, or a shell script in $YTFZF_SORT_NAMES_DIR, that defines the following functions:

  • data_sort_fn()
  • get_sort_by()

Two functions, one sort name, zero drama ✨


πŸ”₯ CUSTOM SCRAPERS πŸ”₯

Custom scrapers are shell scripts located in $YTFZF_CUSTOM_SCRAPERS_DIR. A scraper is responsible for scraping videos from a website and APPENDING them to "$ytfzf_video_json_file" (appending!! not replacing!! don't @ me πŸ’€).

The shell script must be the same shell as your /bin/sh.

Other functions this script may define:

on_startup_<name_of_scraper> β€” this function will be called when the scraper is sourced (which is when the user asks for it). Takes no arguments 🫢

thumbnail_video_info_text_<name_of_scraper> β€” this function shall print information for the thumbnails interface. It's effectively the same as thumbnail_video_info_text().

scrape_next_page_<scraper> β€” this function shall scrape more videos from <scraper>. For it to be called properly with alt+p or ctrl+p, the page it left off on must be written to ${session_cache_dir}/<scraper>-current-page. Where scraper is the name of the scraper with _ instead of -.

<scraper> should be the name put in the "scraper" attribute in VIDEO JSON FORMAT.

This function will happen if the user presses alt+p in fzf.

Takes no arguments.

handle_custom_action_<action_name> β€” this function shall handle a custom action. <action_name> should be the name of the action, replacing any - with _. It takes 1 argument:

  1. The action arguments

Exit codes:

  1. go back to menu
  2. exit

πŸ¦‹ CUSTOM INTERFACES πŸ¦‹

Custom interfaces are shell scripts located in $YTFZF_CUSTOM_INTERFACES_DIR. An interface is responsible for letting the user pick a video from "$ytfzf_video_json_file", then writing the url(s) to "$ytfzf_selected_urls". The shell script must be the same shell as your /bin/sh.

On top of that, the script must also define the function interface_<name_of_interface>, with _ replacing -. This function could handle everything itself, or call another program written in any language to handle it β€” main character energy, your call πŸ‘‘

interface_<name_of_interface> will take a path to the json file holding all data about all the videos as the first argument. The second argument will be a path to a file to store the selected url in, separated by new lines.

Other functions the scraper may define (yes it says scraper here, we're keeping it πŸ’€):

search_prompt_menu_<name_of_interface>() β€” this function should do the same thing as search_prompt_menu(). Takes no arguments. If this function is not defined, search_prompt_menu_ext() will be called instead.

quick_menu_<name_of_interface>() β€” this function should do the same thing as quick_menu(). Takes no arguments. If this function is not defined, quick_menu_ext() will be called instead.

display_text_<name_of_interface>() β€” this function should display text in a way that is copy and pasteable πŸ‘‘ It takes an unlimited number of arguments:

  • ... β€” The text to display

info_wait_prompt_<name_of_interface>() β€” this function should ask the user to pick an info_wait_action option. It should then set the variable info_wait_action equal to the user's choice 🌸 Takes no arguments.

🎨 THUMBNAIL VIEWERS 🎨

Okay so bestie, custom thumbnail viewers? They're just programs that live in $YTFZF_THUMBNAIL_VIEWERS_DIR, and they get called with arguments. Nine of them. Yes, nine. Buckle up 🫢

The arguments are, in order:

  1. An action β€” and there are exactly three actions: start, stop, view, and also no-img. (yes, we know, that reads like four. That's literally what the page says. That's the whole vibe.)
  2. The path to the thumbnail.
  3. The x position (in columns) of the image.
  4. The y position (in lines) of the image.
  5. The width of the image (in columns).
  6. The height of the image (in lines).
  7. The max width of the image (in columns) β€” and don't worry, the width you got already accounts for this πŸ’…
  8. The max height of the image (in lines) β€” and same deal, the height already accounts for this too.
  9. Which side of the terminal to display the image on. The x, y, width and height you got already account for this one as well. This will be one of up, down, left, right.

🧩 EXTENSIONS 🧩

Bestie. Extensions. These are lowkey just extra config files that you load inside your own config file. That's it. That's the whole thing ✨

Where do they live? They should be either in $YTFZF_EXTENSIONS_DIR or in $YTFZF_SYSTEM_ADDON_DIR/extensions.

Heads up fr fr: an extension can do anything a config file can do. And yes, that includes modifying the default utility functions in ytfzf β€” which, no cap, could break the script πŸ’€ So like, be a little careful, okay?

Every extension gets handed a variable called $__loaded_path, and that's the full path to the extension being loaded. Super handy when you need to figure out the current runtime path for the extension you're in. iykyk πŸŽ€

To actually load one, you drop load_extension name-of-extension into $YTFZF_CONFIG_FILE. Boom. Loaded.

And there are two extensions that get loaded automatically, no asking: __ytfzf__ and __ytfzf_multisearch__. Oh and __ytfzf_multisearch__ only loads if $multi_search is 1. Conditional queen πŸ‘‘


🌸 Functions for extensions 🌸

Okay so here's the tea on the functions. Wherever you see <ext>, you swap in the name of the extension β€” and every - in that name becomes _. Just a little name makeover, no big deal πŸ’…

  • on_clean_up_<ext>() β€” runs when the script exits. Takes no arguments. Say your goodbyes 🫢
  • on_no_thumbnail_<ext>() β€” runs when no thumbnail is found. Takes no arguments. We've all been there 😭
  • after_close_url_handler_<ext>() β€” runs after the url handler is closed. Takes no arguments.
  • on_post_set_vars_<ext_name>() β€” swap ext_name for the name of an extension (with - replaced with _). This one is the same as on_post_set_vars.
  • ext_on_search_<ext>() β€” runs before the website is scraped, for every single search query. Takes two arguments:
    1. The current search
    2. The current scrape type
  • post_scrape_<ext>() β€” runs after scraping is complete. Takes no arguments. Cleanup era 🧚
  • on_init_search_<ext>() β€” runs when the search is being initialized. Takes one argument:
    1. The search

🌸 UTILITY FUNCTIONS 🌸

okay so a utility function is literally any function that can be used in configuration files, extensions, thumbnail viewers, interfaces, search-names. These are the little helper besties that make the whole thing work, and they are iconic. Here’s every single one β€” no skips, no cap. ✨

πŸ’… refresh_inv_instances()

This one writes the response from https://api.invidious.io/instances.json?sort_by=type,health,api to $cache_dir/instances.json. It takes no arguments. slay πŸ’–

πŸ¦‹ get_invidious_instances()

This grabs invidious instances that have an api and prints them separated by a new line. It takes no arguments. ✨

πŸŽ€ create_sorted_video_data()

This prints a sorted jsonl string of the scraped videos that can be used in an interface. It takes no arguments. 🫢

🌈 run_interface()

This runs the function interface_<interface_name>, and passes $ytfzf_video_json_file, and $ytfzf_selected_urls. It takes no arguments. πŸ’…

πŸ“ download_thumbnails()

If $skip_thumb_download is 0, this function downloads thumbnails. It takes an unlimited number of arguments formatted in the following way:

<url_name>;<id>

This function should download <url_name> and save it as <id>.jpg in the $thumb_dir folder. πŸ’–

🧚 prepare_for_set_args()

This function sets the variable $OLD_IFS to $IFS, then sets $IFS to the first argument, and lastly it runs set -f. It takes one argument.

  • 1 β€” the new IFS.

🌸 end_of_set_args()

This sets IFS to OLD_IFS. It takes no arguments. πŸŽ€

πŸ’œ modify_ifs()

This sets IFS to the first argument. It takes one argument.

  • 1 β€” the value to set IFS to.

πŸ¦‹ end_modify_ifs()

This unsets $IFS. It takes no arguments. ✨

⭐ mul_str()

This does string multiplication, then prints the result to stdout. It takes two arguments.

  • 1 β€” the string.
  • 2 β€” the amount to duplicate the string.

πŸ’€ remove_ansi_escapes()

This removes ansi escape sequences from a string passed to this function through stdin. It then prints the final string to stdout. It takes no arguments. πŸ™ˆ

πŸ”₯ do_an_event_function()

This runs an event if it exists, then runs event_<ext> for every loaded extension $loaded_extensions, if they exist. It takes an unlimited number of arguments.

  • 1 β€” the name of the event.
  • ... β€” the arguments to pass to event.

πŸ‘‘ detach_cmd()

This detaches a command from the terminal. It takes an unlimited number of arguments.

  • 1 β€” the command to run.
  • ... β€” the arguments to pass to the command.

🌈 source_scrapers()

This goes through each scraper listed in $scrape, and sources the appropriate file. After sourcing the file, it runs the on_startup_<scrape> function, if $__is_fzf_preview is 0. It checks the following locations for the file to source:

  • $YTFZF_CUSTOM_SCRAPERS_DIR
  • $YTFZF_SYSTEM_ADDON_DIR/scrapers
  • $YTFZF_CUSTOM_SCRAPERS_DIR
  • $YTFZF_SYSTEM_ADDON_DIR/scrapers

yes, the same two paths are listed twice in the original β€” no merging, periodt πŸ’…

πŸŽ€ add_commas()

This adds commas to a number (in the standard english way). It gets a number from stdin, and prints the result to stdout. It takes no arguments. ✨

🫢 command_exists()

This checks if a command exists. It exits with status code 0 if it exists, and 1 if it does not. It takes one argument.

  • 1 β€” the command to check.

πŸ’– get_key_value()

This gets the value by a key in a key_value string. A key_value string is formatted like this:

<sep>key=value<sep>...

where <sep> is argument 3, by default a space. If there is only one key_value pair, there must still be <sep> on each side.

After printing the value to stdout, this function sets the variable $KEY_VALUE to the value of the key. It exits with status code 0 if the value is not empty, and 1 if it is empty. It takes three arguments.

  • 1 β€” the key_value string.
  • 2 β€” the key to find the value for.
  • 3 (optional) β€” the separator that separates each key_value pair. By default this is a space.

🌸 title_str()

This capitalizes the first letter of a string, and prints it to stdout. It takes one argument.

  • 1 β€” the string to title.

🧚 shuf()

This function is only created if shuf is not installed. It should act the same as the base functionality of shuf. πŸŽ€

This prints information to stderr, if $log_level is greater than or equal to 2. It takes one argument.

  • 1 β€” the text to print.

This prints a warning to stderr, if $log_level is greater than or equal to 1. It takes one argument.

  • 1 β€” the text to print.

This prints a warning to stderr, if $log_level is greater than or equal to 0. It takes one argument.

  • 1 β€” the text to print.

πŸ‘‘ clean_up()

This kills all ytfzf(1) subprocesses, and removes $session_cache_dir if $session_cache_dir exists, and if $keep_cache equals 0. Lastly, it runs the on_clean_up event. It takes no arguments. πŸ”₯

🌈 is_relative_dir()

This checks if a string is a relative path. It exits with status code 0 if it is relative, and 1 if it is not. It takes one argument.

  • 1 β€” the path to check.

πŸ’– die()

This runs print_error with a string, then exits with a status code. It takes two arguments.

  • 1 β€” the exit status.
  • 2 β€” the text to print with print_error.

πŸŽ€ trim_url()

This reads lines from stdin, and prints the url from them to stdout. The lines should be formatted like this:

text....|url

It takes no arguments. ✨

🫢 get_search_from_source()

This sets _search to a search depending on the source. It takes an unlimited number of arguments.

  • 1 β€” the source to get the search from.
  • ... β€” the arguments to use as the search if $1 is fn-args, or if 1 is not matched, ... is given to get_search_from_<1>.

🧚 load_extension()

This adds an extension to the $loaded_extensions variable, and sources the extension. It checks the following locations for the extension:

  • $YTFZF_EXTENSIONS_DIR
  • $YTFZF_SYSTEM_ADDON_DIR/extensions
  • $PATH

It exits with the same exit code as when the extension was loaded. It takes one argument.

  • 1 β€” the extension to load.

πŸ¦‹ extension_is_loaded()

This checks if an extension is loaded. It takes one argument.

  • 1 β€” the extension to check.

⭐ load_sort_name()

This loads a sort-name. It checks the following locations for the sort-name:

  • $YTFZF_SORT_NAMES_DIR
  • $YTFZF_SYSTEM_ADDON_DIR/sort-names

It exits with status code 1 if the sort-name does not exist, otherwise it exits with the same status code as when the sort-name was loaded. It takes one argument.

  • 1 β€” the sort-name to load.

πŸ’€ load_url_handler()

This sets $url_handler to a url-handler. It checks the following locations for the url-handler:

  • $PATH, and functions in config file
  • $YTFZF_URL_HANDLERS_DIR
  • $YTFZF_SYSTEM_ADDON_DIR/url-handlers

If the url-handler does not exist, this function runs die. It takes one argument.

  • 1 β€” the url-handler to load.

πŸ‘‘ load_interface()

This sets $interface to an interface. If $1 is equal to ext, scripting, or "", $interface is set to 1. It checks the following locations for the interface:

  • $1
  • $YTFZF_CUSTOM_INTERFACES_DIR
  • $YTFZF_SYSTEM_ADDON_DIR/interfaces

It takes one argument.

  • 1 β€” the interface to load.

🌈 load_thumbnail_viewer()

This sets $thumbnail_viewer to a thumbnail-viewer. If $i is equal to a built-in thumbnail-viewer, $thumbnail_viewer is set to that. Otherwise, the following locations are checked:

  • $1
  • $YTFZF_THUMBNAIL_VIEWERS_DIR
  • $YTFZF_SYSTEM_ADDON_DIR

It takes one argument.

  • 1 β€” the thumbnail viewer to load.

πŸ’– _get_request()

This sends a request to a server and prints the response. It takes unlimited arguments.

  • 1 β€” the url to send a request to.
  • ... β€” arguments to pass to curl(1).

This converts a youtube channel link in the form of:

@user
https://www.youtube.com/user/<channel-name>
https://www.youtube.com/c/<channel-name>

It takes one argument.

  • 1 β€” the link to convert.

okay bye bestie πŸ’… this page was ytfzf 2.0, dated 2021 September, and it’s YTFZF(5). βœ¨πŸ’–

πŸ“¦ where this page comes from