YTFZF(5)
π 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_submenuis0, 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_histis1. It is highly recommended to only change this if$__is_submenuis0, or funky things could happen. default:$cache_dir/watch_hist$search_hist_fileβ The file to write search history to if$enable_search_histis1. 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 commandload_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_waitis1. Valid actions:qβ quit (will go back to menu, if$is_loopis1).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 withurl_handler_opts.
π Menu options
$interfaceβ The interface/menu to use. It is recommended to not use this variable directly, instead useload_interface interface-name. Valid options:extβ same as-Dscriptingβ is applied when-a,-r, or-Ais used''β default
$external_menu_lenβ The amount of cols ininterface_ext, (-D). default:210$fzf_preview_sideβ The side to show the preview in fzf. Valid options:leftrightupdowndefault: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 useload_thumbnail_viewer viewer. Valid options:sixeliterm2kittyswaywaylandueberzugchafachafa-16β Uses chafa with 16 colorschafa-ttyβ Uses chafa with 4 colorscatimgcatimg-256β Uses catimg with 256 colorsmpvβ Uses the mpv player to display the images. Works well with tiling window managers.imvβ Similar to mpv, but is a dedicated image viewerswayimgβ Only works on the sway wayland compositorswayimg-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-sortto 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 (usesubmenu_optsinstead). 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 whenfancy_subsis1. default:-------------$fancy_subs_rightβ The text to display on the right of the channel name whenfancy_subsis1. 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-cSscraper as it scrapes youtube not invidious (useSIinstead). For lower internet speeds it is recommended to use default. Available options:maxresmaxresdefaultsddefaulthighβ (default)mediumdefaultstartβ 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:ctrlnext_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_bindsmanually, you gotta manually append this too, no cap.
π― Auto selecting
$is_auto_selectβ auto selects the first-nvideos (only works if$interface=scripting). default:0$is_random_selectβ randomly selects-nvideos (only works if$interface=scripting). default:0$is_specific_selectβ selects a specific video (use$ scripting_video_countto pick which, only works if$interface=scripting). default:0$scripting_video_countβ how many videos to grab with-aor-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,commentsdefault:youtube
$multi_searchβ enables multi search π. default:0$search_sort_byβ the attribute to sort by when searching π:relevance(default)rating(youtube only)upload_dateoldest_first(odysee only)view_count(youtube only)
$search_upload_dateβ search for vids within the last π:hourtodayweekmonthyear
$search_video_durationβ search for long or short vids. possible options:shortlong
$search_result_typeβ the type of results you get π:video(default)playlistchannelall(may not work on some instances, fair warning π)
$nsfwβ searches for nsfw videos inodysee/Oπ. default:false$search_result_featuresβ the features a video should have (comma separated) β :hdsubtitlescreative_commons3dlive4k360locationhdr
$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 prompthistβ use search history.nextβ used internally to use the next search in the list whenmulti_searchis 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 everything1β log only warnings and errors0β 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 withexport, 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 at1.
π οΈ 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>".
π½οΈ Menu related functions
external_menu()β when$interfaceisext_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_sortis1. 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_actionis 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:
titlechanneldurationviewsdateurl
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:
titlechanneldurationviewsdateurl
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_widthmax_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_widthmax_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_widthmax_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_widthmax_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_wimg_hmax_widthmax_heightmax_heightterm_xterm_ycol_px_widthline_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_wimg_hmax_widthmax_heightmax_heightterm_xterm_ycol_px_widthline_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_wimg_hmax_widthmax_heightmax_heightterm_xterm_ycol_px_widthline_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_wimg_hmax_widthmax_heightmax_heightterm_xterm_ycol_px_widthline_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:
- 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:
- 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:
- The search to write
- 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:
- The search query
- 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:
- 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:
- The current option being parsed
- The current option argument being parsed
- The unmodified option being parsed. For an option such as
-a, this value will be the same as$1. However, for every--long-optionthis value will be"-". - 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:
- The optarg
- The raw opt
- 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:
- 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 π:
- go back to menu
- 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 videourl(string): the url to the videotitle(string): the title of the videoscraper(string): The scraper that created the json (used for thumbnails)thumbs(string): a url to a thumbnail/imagechannel(string): the channel nameduration(string): length of the video (standard:[HH:]MM:SS)views(string): amount of views a video hasdate(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:
- The action arguments
Exit codes:
- go back to menu
- 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:
- An action β and there are exactly three actions:
start,stop,view, and alsono-img. (yes, we know, that reads like four. That's literally what the page says. That's the whole vibe.) - The path to the thumbnail.
- The x position (in columns) of the image.
- The y position (in lines) of the image.
- The width of the image (in columns).
- The height of the image (in lines).
- The max width of the image (in columns) β and don't worry, the width you got already accounts for this π
- The max height of the image (in lines) β and same deal, the height already accounts for this too.
- 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>()β swapext_namefor the name of an extension (with-replaced with_). This one is the same ason_post_set_vars.ext_on_search_<ext>()β runs before the website is scraped, for every single search query. Takes two arguments:- The current search
- 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:- 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
IFSto.
π¦ 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. π
π¦ print_info()
This prints information to stderr, if $log_level is greater than or equal to 2. It takes one argument.
- 1 β the text to print.
β print_warning()
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.
π print_error()
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
$1isfn-args, or if1is not matched,...is given toget_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).
π _get_real_channel_link()
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
- alpine 3.24: ytfzf-doc 2.6.2-r0 Β· GPL-3.0-only
- arch rolling: ytfzf 2.6.2-2 Β· GPL-3.0-only
- nixos 26.05: ytfzf 2.6.2
- nixpkgs unstable: ytfzf 2.6.2
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms