Subject: [PATCH v5 2/2] gnu: Add ytfzf.

From: Raghav Gururajan <[email-masked]>
Date: Mon, 5 Jul 2021 11:10:02 -0400

* gnu/packages/image-viewers.scm (ytfzf): New variable.

Co-authored-by: jgart <[email-masked]>
---
 gnu/local.mk                              |   2 +
 gnu/packages/image-viewers.scm            | 173 ++++++
 gnu/packages/patches/ytfzf-programs.patch | 650 ++++++++++++++++++++++
 gnu/packages/patches/ytfzf-updates.patch  |  44 ++
 4 files changed, 869 insertions(+)
 create mode 100644 gnu/packages/patches/ytfzf-programs.patch
 create mode 100644 gnu/packages/patches/ytfzf-updates.patch

diff --git a/gnu/local.mk b/gnu/local.mk
index beaf99bf71..66687b420c 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -1858,6 +1858,8 @@ dist_patch_DATA =						\
   %D%/packages/patches/xsane-support-ipv6.patch			\
   %D%/packages/patches/xsane-tighten-default-umask.patch	\
   %D%/packages/patches/yggdrasil-extra-config.patch	\
+  %D%/packages/patches/ytfzf-programs.patch        \
+  %D%/packages/patches/ytfzf-updates.patch        \
   %D%/packages/patches/ytnef-CVE-2021-3403.patch	\
   %D%/packages/patches/ytnef-CVE-2021-3404.patch	\
   %D%/packages/patches/zstd-CVE-2021-24031_CVE-2021-24032.patch	\
diff --git a/gnu/packages/image-viewers.scm b/gnu/packages/image-viewers.scm
index f01b6a614a..9850aabad6 100644
--- a/gnu/packages/image-viewers.scm
+++ b/gnu/packages/image-viewers.scm
@@ -18,6 +18,8 @@
 ;;; Copyright © 2021 Rovanion Luckey <[email-masked]>
 ;;; Copyright © 2021 Xinglu Chen <[email-masked]>
 ;;; Copyright © 2021 Stefan Reichör <[email-masked]>
+;;; Copyright © 2021 Raghav Gururajan <[email-masked]>
+;;; Copyright © 2021 jgart <[email-masked]>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -46,6 +48,7 @@
   #:use-module (guix build-system python)
   #:use-module (gnu packages autotools)
   #:use-module (gnu packages algebra)
+  #:use-module (gnu packages base)
   #:use-module (gnu packages boost)
   #:use-module (gnu packages check)
   #:use-module (gnu packages compression)
@@ -53,6 +56,7 @@
   #:use-module (gnu packages documentation)
   #:use-module (gnu packages fontutils)
   #:use-module (gnu packages freedesktop)
+  #:use-module (gnu packages gawk)
   #:use-module (gnu packages gettext)
   #:use-module (gnu packages ghostscript)
   #:use-module (gnu packages gl)
@@ -63,7 +67,9 @@
   #:use-module (gnu packages image)
   #:use-module (gnu packages image-processing)
   #:use-module (gnu packages imagemagick)
+  #:use-module (gnu packages linux)
   #:use-module (gnu packages maths)
+  #:use-module (gnu packages ncurses)
   #:use-module (gnu packages perl)
   #:use-module (gnu packages perl-check)
   #:use-module (gnu packages photo)
@@ -71,10 +77,177 @@
   #:use-module (gnu packages python)
   #:use-module (gnu packages python-xyz)
   #:use-module (gnu packages qt)
+  #:use-module (gnu packages suckless)
+  #:use-module (gnu packages terminals)
+  #:use-module (gnu packages video)
+  #:use-module (gnu packages web)
   #:use-module (gnu packages xdisorg)
   #:use-module (gnu packages xorg)
   #:use-module (gnu packages))
 
+(define-public ytfzf
+  (package
+    (name "ytfzf")
+    (version "1.2.0")
+    (home-page "https://github.com/pystardust/ytfzf")
+    (source
+     (origin
+       (method git-fetch)
+       (uri
+        (git-reference
+         (url home-page)
+         (commit (string-append "v" version))))
+       (file-name (git-file-name name version))
+       (sha256
+        (base32 "00d416qb4109pm77ikhnmds8qng90ni2jan9kdnxz7b6sh5f61nz"))))
+    (build-system gnu-build-system)
+    (arguments
+     `(#:tests? #f                      ;no test suite
+       #:modules
+       ((guix build gnu-build-system)
+        (guix build utils)
+        (srfi srfi-26))
+       #:phases
+       (modify-phases %standard-phases
+         (add-after 'unpack 'apply-patches
+           (lambda* (#:key inputs #:allow-other-keys)
+             ;; Pre-requisite for 'patch-script' phase.
+             (invoke "patch" "--input"
+                     (assoc-ref inputs "ytfzf-programs"))
+             ;; Disables self-update.
+             (invoke "patch" "--input"
+                     (assoc-ref inputs "ytfzf-updates"))))
+         (add-after 'apply-patches 'patch-script
+           (lambda* (#:key inputs outputs #:allow-other-keys)
+             (let* ((out (assoc-ref outputs "out"))
+                    (catimg (assoc-ref inputs "catimg"))
+                    (chafa (assoc-ref inputs "chafa"))
+                    (coreutils (assoc-ref inputs "coreutils"))
+                    (curl (assoc-ref inputs "curl"))
+                    (dmenu (assoc-ref inputs "dmenu"))
+                    (fzf (assoc-ref inputs "fzf"))
+                    (gawk (assoc-ref inputs "gawk"))
+                    (grep (assoc-ref inputs "grep"))
+                    (jp2a (assoc-ref inputs "jp2a"))
+                    (jq (assoc-ref inputs "jq"))
+                    (libnotify (assoc-ref inputs "libnotify"))
+                    (mpv (assoc-ref inputs "mpv"))
+                    (ncurses (assoc-ref inputs "ncurses"))
+                    (python-ueberzug (assoc-ref inputs "python-ueberzug"))
+                    (sed (assoc-ref inputs "sed"))
+                    (util-linux (assoc-ref inputs "util-linux"))
+                    (youtube-dl (assoc-ref inputs "youtube-dl")))
+               ;; Use correct $PREFIX path.
+               (substitute* "Makefile"
+                 (("/usr/bin")
+                  (string-append out "/bin")))
+               ;; Use absolute path for referenced programs.
+               (substitute* "ytfzf"
+                 (("@awk@")
+                  (string-append gawk "/bin/awk"))
+                 (("@cat@")
+                  (string-append coreutils "/bin/cat"))
+                 (("@catimg@")
+                  (string-append catimg "/bin/catimg"))
+                 (("@chafa@")
+                  (string-append chafa "/bin/chafa"))
+                 (("@chmod@")
+                  (string-append coreutils "/bin/chmod"))
+                 (("@column@")
+                  (string-append util-linux "/bin/column"))
+                 (("@cp@")
+                  (string-append coreutils "/bin/cp"))
+                 (("@cut@")
+                  (string-append coreutils "/bin/cut"))
+                 (("@curl@")
+                  (string-append curl "/bin/curl"))
+                 (("@date@")
+                  (string-append coreutils "/bin/date"))
+                 (("@dmenu@")
+                  (string-append dmenu "/bin/dmenu"))
+                 (("@fzf@")
+                  (string-append fzf "/bin/fzf"))
+                 (("@grep@")
+                  (string-append grep "/bin/grep"))
+                 (("@head@")
+                  (string-append coreutils "/bin/head"))
+                 (("@jp2a@")
+                  (string-append jp2a "/bin/jp2a"))
+                 (("@jq@")
+                  (string-append jq "/bin/jq"))
+                 (("@mkdir@")
+                  (string-append coreutils "/bin/mkdir"))
+                 (("@mkfifo@")
+                  (string-append coreutils "/bin/mkfifo"))
+                 (("@mpv@")
+                  (string-append mpv "/bin/mpv"))
+                 (("@nohup@")
+                  (string-append coreutils "/bin/nohup"))
+                 (("@notify-send@")
+                  (string-append libnotify "/bin/notify-send"))
+                 (("@rm@")
+                  (string-append coreutils "/bin/rm"))
+                 (("@sed@")
+                  (string-append sed "/bin/sed"))
+                 (("@seq@")
+                  (string-append coreutils "/bin/seq"))
+                 (("@setsid@")
+                  (string-append util-linux "/bin/setsid"))
+                 (("@sleep@")
+                  (string-append coreutils "/bin/sleep"))
+                 (("@sort@")
+                  (string-append coreutils "/bin/sort"))
+                 (("@tput@")
+                  (string-append ncurses "/bin/tput"))
+                 (("@tr@")
+                  (string-append coreutils "/bin/tr"))
+                 (("@ueberzug@")
+                  (string-append python-ueberzug "/bin/ueberzug"))
+                 (("@uname@")
+                  (string-append coreutils "/bin/uname"))
+                 (("@uniq@")
+                  (string-append coreutils "/bin/uniq"))
+                 (("@wc@")
+                  (string-append coreutils "/bin/wc"))
+                 (("@youtube-dl@")
+                  (string-append youtube-dl "/bin/youtube-dl"))))
+             (substitute* "ytfzf"
+               ;; Generate temporary files in the user-specific path,
+               ;; to avoid issues in multi-user systems.
+               (("/tmp/ytfzf")
+                "$HOME/.cache/ytfzf")
+               ;; Report errors to Guix.
+               (("report at: https://github.com/pystardust/ytfzf")
+                "report at: https://issues.guix.gnu.org"))))
+         (delete 'configure))))         ;no configure script
+    (native-inputs
+     `(("ytfzf-programs"
+        ,(search-patch "ytfzf-programs.patch"))
+       ("ytfzf-updates"
+        ,(search-patch "ytfzf-updates.patch"))))
+    (inputs
+     `(("catimg" ,catimg)
+       ("chafa" ,chafa)
+       ("coreutils" ,coreutils)
+       ("curl" ,curl)
+       ("dmenu" ,dmenu)
+       ("fzf" ,fzf)
+       ("gawk" ,gawk)
+       ("grep" ,grep)
+       ("jp2a" ,jp2a)
+       ("jq" ,jq)
+       ("libnotify" ,libnotify)
+       ("mpv" ,mpv)
+       ("ncurses" ,ncurses)
+       ("python-ueberzug" ,python-ueberzug)
+       ("sed" ,sed)
+       ("util-linux" ,util-linux)
+       ("youtube-dl" ,youtube-dl)))
+    (synopsis "Watch PeerTube or YouTube videos from the terminal")
+    (description "@code{ytfzf} is a POSIX script that helps you find PeerTube or
+YouTube videos without requiring API and opens/downloads them using mpv/ytdl.")
+    (license license:gpl3+)))
+
 (define-public feh
   (package
     (name "feh")
diff --git a/gnu/packages/patches/ytfzf-programs.patch b/gnu/packages/patches/ytfzf-programs.patch
new file mode 100644
index 0000000000..fc7684d3ef
--- /dev/null
+++ b/gnu/packages/patches/ytfzf-programs.patch
@@ -0,0 +1,650 @@
+From 291a0cd6e24026da0cfd2007e48c00f0824bd0d2 Mon Sep 17 00:00:00 2001
+From: Raghav Gururajan <[email-masked]>
+Date: Mon, 5 Jul 2021 06:45:49 -0400
+Subject: [PATCH 1/2] Modify the strings of referenced programs.
+
+Pattern the strings of referenced programs, so that they can be easily
+substituted with absolute paths using a custom-phase.
+
+Co-authored-by: jgart <[email-masked]>
+---
+ ytfzf | 202 +++++++++++++++++++++++++++++-----------------------------
+ 1 file changed, 101 insertions(+), 101 deletions(-)
+
+diff --git a/ytfzf b/ytfzf
+index f4d2e0d..0a2c372 100755
+--- a/ytfzf
++++ b/ytfzf
+@@ -49,19 +49,19 @@ cache_dir=${YTFZF_CACHE-${cache_dir-$HOME/.cache/ytfzf}}
+ #video type preference (mp4/1080p, mp4/720p, etc..)
+ video_pref=${YTFZF_PREF-${video_pref-}}
+ #the menu to use instead of fzf when -D is specified
+-external_menu=${YTFZF_EXTMENU-${external_menu-dmenu -i -l 30 -p Search:}}
++external_menu=${YTFZF_EXTMENU-${external_menu-@dmenu@ -i -l 30 -p Search:}}
+ #number of columns (characters on a line) the external menu can have
+ #necessary for formatting text for external menus
+ external_menu_len=${YTFZF_EXTMENU_LEN-${external_menu_len-220}}
+ #player settings (players need to support streaming with youtube-dl)
+ #player to use for watching the video
+-video_player=${YTFZF_PLAYER-${video_player-mpv}}
++video_player=${YTFZF_PLAYER-${video_player-@mpv@}}
+ #if YTFZF_PREF is specified, use this player instead
+-video_player_format=${YTFZF_PLAYER_FORMAT-${video_player_format-mpv --ytdl-format=}}
++video_player_format=${YTFZF_PLAYER_FORMAT-${video_player_format-@mpv@ --ytdl-format=}}
+ #player to use for audio only
+-audio_player=${YTFZF_AUDIO_PLAYER-${audio_player-mpv --no-video}}
++audio_player=${YTFZF_AUDIO_PLAYER-${audio_player-@mpv@ --no-video}}
+ #the command to use for displaying thumbnails
+-thumb_disp_method=${YTFZF_THUMB_DISP_METHOD-${thumb_disp_method-ueberzug}}
++thumb_disp_method=${YTFZF_THUMB_DISP_METHOD-${thumb_disp_method-@ueberzug@}}
+ #Storing the argument and location for autogenerated subtitles
+ [ -z "$YTFZF_SUBT_NAME" ] && YTFZF_SUBT_NAME=""
+ #Stores the language for the auto genereated subtitles
+@@ -85,8 +85,8 @@ subscriptions_file=${subscriptions_file-$config_dir/subscriptions}
+ #> stores the pid of running ytfzf sessions
+ pid_file="$cache_dir/.pid"
+ #> make folders that don't exist
+-[ -d "$cache_dir" ] || mkdir -p "$cache_dir"
+-[ -d "$thumb_dir" ] || mkdir -p "$thumb_dir"
++[ -d "$cache_dir" ] || @mkdir@ -p "$cache_dir"
++[ -d "$thumb_dir" ] || @mkdir@ -p "$thumb_dir"
+ 
+ #> config settings
+ #list of shortcuts to use in fzf
+@@ -177,12 +177,12 @@ dep_ck () {
+ 	done
+ 	unset Dep
+ }
+-dep_ck "jq" "youtube-dl" "curl"
++dep_ck "@jq@" "@youtube-dl@" "@curl@"
+ 
+ 
+ #only check for mpv if $YTFZF_PLAYER is set to it
+ #don't check $YTFZF_PLAYER as it could be multiple commands
+-[ "$video_player" = "mpv" ] && dep_ck "mpv"
++[ "$video_player" = "@mpv@" ] && dep_ck "@mpv@"
+ 
+ ############################
+ #       Help Texts         #
+@@ -326,8 +326,8 @@ print_info () {
+ }
+ 
+ print_error () {
+-    [ $ext_menu_notifs -eq 1 ] && notify-send "error" "$*" || printf "\033[31m$*\033[0m" >&2
+-    [ $ext_menu_notifs -eq 1 ] && notify-send "Check for new versions and report at: https://github.com/pystardust/ytfzf\n" || printf "Check for new versions and report at: https://github.com/pystardust/ytfzf\n" >&2
++    [ $ext_menu_notifs -eq 1 ] && @notify-send@ "error" "$*" || printf "\033[31m$*\033[0m" >&2
++    [ $ext_menu_notifs -eq 1 ] && @notify-send@ "Check for new versions and report at: https://github.com/pystardust/ytfzf\n" || printf "Check for new versions and report at: https://github.com/pystardust/ytfzf\n" >&2
+ }
+ 
+ ############################
+@@ -398,12 +398,12 @@ format_fzf () {
+ format_menu () {
+ 	if [ "$is_ext_menu" -eq 0 ]; then
+ 		#dep_ck fzf here because it is only necessary to use here
+-		dep_ck "fzf"
+-		menu_command='column -t -s "$tab_space" | fzf -m --bind change:top --tabstop=1 --layout=reverse --delimiter="$tab_space" --nth=1,2 --expect="$shortcuts" $FZF_DEFAULT_OPTS'
++		dep_ck "@fzf@"
++		menu_command='@column@ -t -s "$tab_space" | @fzf@ -m --bind change:top --tabstop=1 --layout=reverse --delimiter="$tab_space" --nth=1,2 --expect="$shortcuts" $FZF_DEFAULT_OPTS'
+ 		format_fzf
+ 	else
+ 		# Dmenu doesn't render tabs so removing it
+-		menu_command='tr -d "$tab_space" | '"$external_menu"
++		menu_command='@tr@ -d "$tab_space" | '"$external_menu"
+ 		format_ext_menu
+ 	fi
+ }
+@@ -461,13 +461,13 @@ ID="ytfzf-ueberzug"
+ WIDTH=$FZF_PREVIEW_COLUMNS
+ HEIGHT=$FZF_PREVIEW_LINES
+ start_ueberzug () {
+-    [ -e $FIFO ] || { mkfifo "$FIFO" || exit 1 ; }
+-    ueberzug layer --parser json --silent < "$FIFO" &
++    [ -e $FIFO ] || { @mkfifo@ "$FIFO" || exit 1 ; }
++    @ueberzug@ layer --parser json --silent < "$FIFO" &
+     exec 3>"$FIFO"
+ }
+ stop_ueberzug () {
+     exec 3>&-
+-    rm "$FIFO" > /dev/null 2>&1
++    @rm@ "$FIFO" > /dev/null 2>&1
+ }
+ 
+ preview_img () {
+@@ -476,12 +476,12 @@ preview_img () {
+ 	shorturl=${args##*${tab_space}|}
+ 	shorturl="${shorturl%% *}"
+ 
+-	json_obj=$(printf "%s" "$videos_json" | jq '.[]|select( .videoID == "'"$shorturl"'")')
++	json_obj=$(printf "%s" "$videos_json" | @jq@ '.[]|select( .videoID == "'"$shorturl"'")')
+ 
+ 
+ 	IFS=$tab_space read -r title channel duration views date description <<-EOF
+ 	$(
+-		printf "%s" "$json_obj" | jq -r \
++		printf "%s" "$json_obj" | @jq@ -r \
+ 		'
+ 		[.title,.channel,.duration,.views,.date,.description]|@tsv
+ 		'
+@@ -530,31 +530,31 @@ preview_img () {
+ 		} > "$FIFO" ;;
+ 	    catimg)
+ 		printf "\n"
+-		catimg -w "$((thumb_width * 2))" "$IMAGE" ;;
++		@catimg@ -w "$((thumb_width * 2))" "$IMAGE" ;;
+ 	    jp2a)
+ 		printf "\n"
+-		jp2a --size="${thumb_width}x$((thumb_height / 2))" --colors  --color-depth=24 "$IMAGE" ;;
++		@jp2a@ --size="${thumb_width}x$((thumb_height / 2))" --colors  --color-depth=24 "$IMAGE" ;;
+ 	    jp2a-8)
+ 		printf "\n"
+-		jp2a --size="${thumb_width}x$((thumb_height / 2))" --colors  --color-depth=8 "$IMAGE" ;;
++		@jp2a@ --size="${thumb_width}x$((thumb_height / 2))" --colors  --color-depth=8 "$IMAGE" ;;
+ 	    jp2a-4)
+ 		printf "\n"
+-		jp2a --size="${thumb_width}x$((thumb_height / 2))" --colors  --color-depth=4 "$IMAGE" ;;
++		@jp2a@ --size="${thumb_width}x$((thumb_height / 2))" --colors  --color-depth=4 "$IMAGE" ;;
+ 	    jp2a-gray|jp2a-grey)
+ 		printf "\n"
+-		jp2a --size="${thumb_width}x$((thumb_height / 2))" "$IMAGE" ;;
++		@jp2a@ --size="${thumb_width}x$((thumb_height / 2))" "$IMAGE" ;;
+ 	    chafa)
+ 		printf "\n"
+-		chafa --size="${thumb_width}x${thumb_height}" "$IMAGE" ;;
++		@chafa@ --size="${thumb_width}x${thumb_height}" "$IMAGE" ;;
+ 	    chafa-gray|chafa-grey)
+ 		printf "\n"
+-		chafa --size="${thumb_width}x${thumb_height}" --colors=2 "$IMAGE" ;;
++		@chafa@ --size="${thumb_width}x${thumb_height}" --colors=2 "$IMAGE" ;;
+ 	    chafa-4)
+ 		printf "\n"
+-		chafa --size="${thumb_width}x${thumb_height}" --colors=16 "$IMAGE" ;;
++		@chafa@ --size="${thumb_width}x${thumb_height}" --colors=16 "$IMAGE" ;;
+ 	    chafa-8)
+ 		printf "\n"
+-		chafa --size="${thumb_width}x${thumb_height}" --colors=256 "$IMAGE" ;;
++		@chafa@ --size="${thumb_width}x${thumb_height}" --colors=256 "$IMAGE" ;;
+ 	    custom)
+ 		if ! function_exists "handle_display_img"; then
+ 		    printf "\033[031mERROR[#07]: \033[0m\033[1mhandle_display_img\033[0m is not defined" >&2
+@@ -585,20 +585,20 @@ download_thumbnails () {
+ 	if [ "$thumbnail_quality" -eq 1 ]; then
+ 		image_download () {
+ 			# higher quality images
+-			curl -s "$Url" -G --data-urlencode "sqp=" > "$thumb_dir/$Name.png"
++			@curl@ -s "$Url" -G --data-urlencode "sqp=" > "$thumb_dir/$Name.png"
+ 		}
+ 	else
+ 		image_download () {
+- 			curl -s "$Url"  > "$thumb_dir/$Name.png"
++			@curl@ -s "$Url"  > "$thumb_dir/$Name.png"
+ 		}
+ 	fi
+ 
+ 	print_info "Downloading Thumbnails...\n"
+ 	thumb_urls=$(printf "%s" "$*" |\
+-		jq  -r '.[]|[.thumbs,.videoID]|@tsv' )
++		@jq@  -r '.[]|[.thumbs,.videoID]|@tsv' )
+ 
+ 	while IFS=$tab_space read -r Url Name; do
+-	    sleep 0.001
++	    @sleep@ 0.001
+ 		{
+ 			image_download
+ 		} &
+@@ -628,7 +628,7 @@ get_sp_filter () {
+ 	#another example is sort by filter + upload date filter only changes one character as well
+ 	if [ -n "$filter_id" ]; then
+ 		#gets the character in the filter_id that needs to be replaced if upload_date_filter is also given
+-		upload_date_character=$(printf "%s" "$filter_id" | awk '{print substr($1, 8, 1)}')
++		upload_date_character=$(printf "%s" "$filter_id" | @awk@ '{print substr($1, 8, 1)}')
+ 	fi
+ 
+ 	#For each of these, if upload_date_character is unset, the filter_id should be the normal filter
+@@ -650,7 +650,7 @@ get_sp_filter () {
+ 	if [ -n "$upload_date_character" ]; then
+ 		#replaces the 8th character in the filter_id with the appropriate character
+ 		#the 8th character specifies the upload_date_filter
+-		sp=$(printf "%s" "$filter_id" | sed 's/\(.\{7\}\)./\1'"$upload_date_character"'/')
++		sp=$(printf "%s" "$filter_id" | @sed@ 's/\(.\{7\}\)./\1'"$upload_date_character"'/')
+ 	#otherwise set it to the filter_id
+ 	else
+ 		sp=$filter_id
+@@ -660,15 +660,15 @@ get_sp_filter () {
+ 
+ get_yt_json () {
+ 	# scrapes the json embedded in the youtube html page
+-	printf "%s" "$*" | sed -n '/var *ytInitialData/,$p' | tr -d '\n' |\
+-        sed -E ' s_^.*var ytInitialData ?=__ ; s_;</script>.*__ ;'
++	printf "%s" "$*" | @sed@ -n '/var *ytInitialData/,$p' | @tr@ -d '\n' |\
++        @sed@ -E ' s_^.*var ytInitialData ?=__ ; s_;</script>.*__ ;'
+ }
+ 
+ get_yt_html () {
+     link=$1
+     query=$2
+     printf "%s" "$(
+-	curl "$link" -s \
++	@curl@ "$link" -s \
+ 	  -G --data-urlencode "search_query=$query" \
+ 	  -G --data-urlencode "sp=$sp" \
+ 	  -H 'Authority: www.youtube.com' \
+@@ -684,7 +684,7 @@ get_video_data () {
+ 	# outputs tab and pipe separated fields: title, channel, view count, video length, video upload date, and the video id/url
+ 	# from the videos_json
+ 	printf "%s" "$*" |\
+-	    jq -r '.[]| "\(.title)'"$tab_space"'|\(.channel)'"$tab_space"'|\(.views)'"$tab_space"'|\(.duration)'"$tab_space"'|\(.date)'"$tab_space"'|\(.videoID)"'
++	    @jq@ -r '.[]| "\(.title)'"$tab_space"'|\(.channel)'"$tab_space"'|\(.views)'"$tab_space"'|\(.duration)'"$tab_space"'|\(.date)'"$tab_space"'|\(.videoID)"'
+ }
+ 
+ scrape_channel () {
+@@ -694,7 +694,7 @@ scrape_channel () {
+ 	channel_url=$*
+ 
+ 	# Converting channel title page url to channel video url
+-	if ! printf "%s" "$channel_url" | grep -q '/videos *$'; then
++	if ! printf "%s" "$channel_url" | @grep@ -q '/videos *$'; then
+ 		channel_url=${channel_url%/featured}/videos
+ 	fi
+ 
+@@ -706,8 +706,8 @@ scrape_channel () {
+ 	fi
+ 
+ 	#gets the channel name from title of page
+-	channel_name=$(printf "%s" "$yt_html" | grep -o '<title>.*</title>' |
+-		sed \
++	channel_name=$(printf "%s" "$yt_html" | @grep@ -o '<title>.*</title>' |
++		@sed@ \
+ 		-e 's/ - YouTube//' \
+ 		-e 's/<\/\?title>//g' \
+ 		-e "s/&apos;/'/g" \
+@@ -723,7 +723,7 @@ scrape_channel () {
+ 
+ 	#gets a list of videos
+ 	videos_json=$(printf "%s" "$yt_json" |\
+-	jq '[ .contents | ..|.gridVideoRenderer? |
++	@jq@ '[ .contents | ..|.gridVideoRenderer? |
+ 	select(. !=null) |
+ 	    {
+ 	    	title: .title.runs[0].text,
+@@ -736,7 +736,7 @@ scrape_channel () {
+ 	    }
+ 	]')
+ 
+-	videos_json=$(printf "%s" "$videos_json" | jq '.[0:'$sub_link_count']')
++	videos_json=$(printf "%s" "$videos_json" | @jq@ '.[0:'$sub_link_count']')
+ 	printf "%s\n" "$videos_json" >> "$tmp_video_json_file"
+ 	#checks if it's empty in case it was defined in a config function eg: on_get_search
+ 	[ -z "$videos_data" ] && videos_data=$(get_video_data "$videos_json")
+@@ -768,11 +768,11 @@ get_trending_url_data () {
+ scrape_pt () {
+      #gets a list of videos
+      pt_json=$(
+-     curl \
++     @curl@ \
+          -s "https://sepiasearch.org/api/v1/search/videos" \
+ 	 -G --data-urlencode "search=$*") 
+      videos_json=$(printf "%s" "$pt_json" |\
+-	jq '[ .data | .[] |
++	@jq@ '[ .data | .[] |
+ 	    {
+ 		title: .name,
+ 		channel: .channel.displayName,
+@@ -829,7 +829,7 @@ scrape_yt () {
+ 	fi
+ 
+ 	#gets a list of videos
+-	videos_json=$(printf "%s" "$yt_json" | jq '[ .contents|
++	videos_json=$(printf "%s" "$yt_json" | @jq@ '[ .contents|
+ 	..|.videoRenderer? |
+ 	select(. !=null) |
+ 		{
+@@ -844,7 +844,7 @@ scrape_yt () {
+ 		}
+ 	]')
+ 
+-	playlist_json=$(printf "%s" "$yt_json" | jq '[ .contents|
++	playlist_json=$(printf "%s" "$yt_json" | @jq@ '[ .contents|
+ 	..|.playlistRenderer? |
+ 	select(. !=null) |
+ 		{
+@@ -904,31 +904,31 @@ get_search_query () {
+ #> To select videos from videos_data
+ user_selection () {
+ 	#remove subscription separators
+-	videos_data_clean=$(printf "%s" "$videos_data" | sed "/.*$tab_space$/d")
++	videos_data_clean=$(printf "%s" "$videos_data" | @sed@ "/.*$tab_space$/d")
+ 
+ 	#$selected_data is the video the user picked
+ 	#picks the first n videos
+ 	if [ "$select_all" -eq 1 ] ; then
+ 		selected_data=$videos_data_clean
+ 	elif [ "$auto_select" -eq 1 ] ; then
+-		selected_data=$(printf "%s\n" "$videos_data_clean" | sed "${link_count}"q )
++		selected_data=$(printf "%s\n" "$videos_data_clean" | @sed@ "${link_count}"q )
+ 	#picks n random videos
+ 	elif [ "$random_select" -eq 1 ] ; then
+-	    selected_data=$(printf "%s\n" "$videos_data_clean" | posix_shuf | head -n${link_count}) 
++	    selected_data=$(printf "%s\n" "$videos_data_clean" | posix_shuf | @head@ -n${link_count})
+ 	    #posix_shuf, pick the first $link_count videos
+ 
+ 	#show thumbnail menu
+ 	elif [ "$show_thumbnails" -eq 1 ] ; then
+-		dep_ck "ueberzug" "fzf"
++		dep_ck "@ueberzug@" "@fzf@"
+ 		export YTFZF_THUMB_DISP_METHOD="$thumb_disp_method"
+-		[ "$thumb_disp_method" = "ueberzug" ] && start_ueberzug
++		[ "$thumb_disp_method" = "@ueberzug@" ] && start_ueberzug
+ 		#thumbnails only work in fzf, use fzf
+-		menu_command="fzf -m --tabstop=1 --bind change:top --delimiter=\"$tab_space\" \
++		menu_command="@fzf@ -m --tabstop=1 --bind change:top --delimiter=\"$tab_space\" \
+ 		--nth=1,2 --expect='$shortcuts' $FZF_DEFAULT_OPTS \
+ 		--layout=reverse --preview \"sh $0 -U {}\" \
+         	--preview-window \"$PREVIEW_SIDE:50%:noborder:wrap\""
+ 		selected_data=$( title_len=200 video_menu "$videos_data" )
+-		[ "$thumb_disp_method" = "ueberzug" ] && stop_ueberzug
++		[ "$thumb_disp_method" = "@ueberzug@" ] && stop_ueberzug
+ 		# Deletes thumbnails if no video is selected
+ 		[ -z "$selected_data" ] && clean_up
+ 	#show regular menu
+@@ -951,10 +951,10 @@ handle_shortcuts () {
+     case $selected_key in
+ 	"$urls_shortcut") printf "%s\n" $selected_urls; return 1 ;;
+ 	"$title_shortcut") 
+-	    printf "%s\n" "$selected_data" | awk -F "  " '{print $1}'; return 1 ;;
++	    printf "%s\n" "$selected_data" | @awk@ -F "  " '{print $1}'; return 1 ;;
+ 	"$open_browser_shortcut")
+ 	    for url in $selected_urls; do
+-		nohup $BROWSER "$url" >/dev/null 2>&1
++		@nohup@ $BROWSER "$url" >/dev/null 2>&1
+ 	    done
+ 	    return 1 ;;
+ 	"$watch_shortcut") is_download=0; is_audio_only=0; return 0;;
+@@ -988,10 +988,10 @@ format_user_selection () {
+ 			11) selected_urls=$selected_urls$new_line'https://www.youtube.com/watch?v='$surl ;;
+ 			34) selected_urls=$selected_urls$new_line'https://www.youtube.com/playlist?list='$surl ;;
+ 			36)
+-			    selected_urls=$selected_urls$new_line"$(printf "%s" "$videos_json" | jq '.[].url' | grep -F "$surl" | tr -d '"')" ;;
++			    selected_urls=$selected_urls$new_line"$(printf "%s" "$videos_json" | @jq@ '.[].url' | @grep@ -F "$surl" | @tr@ -d '"')" ;;
+ 			*) continue ;;
+ 		esac
+-		refined_selected_data=$refined_selected_data$new_line$(printf '%s' "$videos_data" | grep "|$surl" )
++		refined_selected_data=$refined_selected_data$new_line$(printf '%s' "$videos_data" | @grep@ "|$surl" )
+ 	done<<-EOF
+ 	$selected_data
+ 	EOF
+@@ -1014,9 +1014,9 @@ print_data () {
+ get_video_format () {
+ 	# select format if flag given
+ 	[ $show_format -eq 0 ] && return
+-        formats=$(youtube-dl -F "$(printf "$selected_urls")") 
+-        line_number=$(printf "$formats" | grep -n '.*extension  resolution.*' | cut -d: -f1)
+-        quality=$(printf "$formats \n1 2 xAudio" | awk -v lineno=$line_number 'FNR > lineno {print $3}' | sort -n |  awk -F"x" '{print $2 "p"}' | uniq | sed -e "s/Audiop/Audio/" -e "/^p$/d" | eval "$menu_command" | sed "s/p//g")
++        formats=$(@youtube-dl@ -F "$(printf "$selected_urls")")
++        line_number=$(printf "$formats" | @grep@ -n '.*extension  resolution.*' | @cut@ -d: -f1)
++        quality=$(printf "$formats \n1 2 xAudio" | @awk@ -v lineno=$line_number 'FNR > lineno {print $3}' | @sort@ -n |  @awk@ -F"x" '{print $2 "p"}' | @uniq@ | @sed@ -e "s/Audiop/Audio/" -e "/^p$/d" | eval "$menu_command" | @sed@ "s/p//g")
+ 		[ -z "$quality"  ] && exit;
+ 		[ $quality = "Audio"  ] && video_pref= && video_player="$audio_player" || video_pref="bestvideo[height=?$quality][vcodec!=?vp9]+bestaudio/best"
+ 
+@@ -1026,9 +1026,9 @@ get_video_format () {
+ get_sub_lang () {
+     if [ $auto_caption -eq 1 ]; then
+         #Gets the auto generated subs and stores them in a file
+-        sub_list=$(youtube-dl --list-subs  --write-auto-sub "$selected_urls" | sed '/Available subtitles/,$d' | awk '{print $1}' | sed '1d;2d;3d')
++        sub_list=$(@youtube-dl@ --list-subs  --write-auto-sub "$selected_urls" | @sed@ '/Available subtitles/,$d' | @awk@ '{print $1}' | @sed@ '1d;2d;3d')
+         if [ -n "$sub_list" ]; then
+-            [ -n "$selected_sub" ] ||  selected_sub=$(printf "$sub_list" | eval "$menu_command") &&  youtube-dl  --sub-lang $selected_sub  --write-auto-sub --skip-download "$selected_urls" -o /tmp/ytfzf && YTFZF_SUBT_NAME="--sub-file=/tmp/ytfzf.$selected_sub.vtt" || printf "Auto generated subs not available."
++            [ -n "$selected_sub" ] ||  selected_sub=$(printf "$sub_list" | eval "$menu_command") &&  @youtube-dl@  --sub-lang $selected_sub  --write-auto-sub --skip-download "$selected_urls" -o /tmp/ytfzf && YTFZF_SUBT_NAME="--sub-file=/tmp/ytfzf.$selected_sub.vtt" || printf "Auto generated subs not available."
+         fi
+ 	unset sub_list
+     fi
+@@ -1046,10 +1046,10 @@ open_player () {
+ 	if [ $detach_player -eq 1 ]; then
+ 		if [ -z "$video_pref" ] || [ $is_audio_only -eq 1 ]; then
+ 			printf "Opening Player: %s\n" "$video_player $*"
+-			setsid -f $video_player "$@"  $YTFZF_SUBT_NAME >/dev/null 2>&1
++			@setsid@ -f $video_player "$@"  $YTFZF_SUBT_NAME >/dev/null 2>&1
+ 		else
+ 			printf "Opening Player: %s\n" "$video_player_format$video_pref $*"
+-			setsid -f $video_player_format"$video_pref"  "$@"  $YTFZF_SUBT_NAME >/dev/null 2>&1
++			@setsid@ -f $video_player_format"$video_pref"  "$@"  $YTFZF_SUBT_NAME >/dev/null 2>&1
+ 		fi
+ 		return
+ 	fi
+@@ -1064,9 +1064,9 @@ open_player () {
+ 		fi
+ 	elif [ $is_download -eq 1 ]; then
+ 		if [ -z "$video_pref" ]; then
+-			youtube-dl "$@"  "$YTFZF_SUBT_NAME"
++			@youtube-dl@ "$@"  "$YTFZF_SUBT_NAME"
+ 		else
+-			youtube-dl -f "$video_pref"  "$@"  $YTFZF_SUBT_NAME || video_pref= open_player "$@"
++			@youtube-dl@ -f "$video_pref"  "$@"  $YTFZF_SUBT_NAME || video_pref= open_player "$@"
+ 		fi
+ 	fi
+ }
+@@ -1087,7 +1087,7 @@ play_url () {
+ 	fi
+ 
+ 	#Delete the temp auto-gen subtitle file
+-	[ $auto_caption -eq 1 ] && rm -f "${YTFZF_SUBT_NAME#*=}"
++	[ $auto_caption -eq 1 ] && @rm@ -f "${YTFZF_SUBT_NAME#*=}"
+ 
+ 	unset player_urls
+ }
+@@ -1102,7 +1102,7 @@ session_is_running () {
+ #> removes tmp files and clutter
+ clean_up () {
+ 	if ! session_is_running ; then
+-		[ -d "$thumb_dir" ] && rm -r "$thumb_dir"
++		[ -d  "$thumb_dir" ] && @rm@ -r "$thumb_dir"
+ 		: > "$pid_file"
+ 		function_exists "on_exit" && on_exit
+ 	fi
+@@ -1124,9 +1124,9 @@ save_before_exit () {
+ check_if_url () {
+ 	# to check if given input is a url
+ 	url_regex='^https\?://.*'
+-	if printf "%s" "$1" | grep -q "$url_regex"; then
++	if printf "%s" "$1" | @grep@ -q "$url_regex"; then
+ 		is_url=1
+-		selected_urls=$(printf "%s" "$1" | tr ' ' '\n')
++		selected_urls=$(printf "%s" "$1" | @tr@ ' ' '\n')
+ 		scrape="url"
+ 	else
+ 		is_url=0
+@@ -1139,10 +1139,10 @@ get_history () {
+ 	if [ "$enable_hist" -eq 1 ]; then
+ 		[ -e "$history_file" ] || : > "$history_file"
+ 		#gets history data in reverse order (makes it most recent to least recent)
+-		hist_data=$( sed '1!G; h; $!d' "$history_file" )
++		hist_data=$( @sed@ '1!G; h; $!d' "$history_file" )
+ 		[ -z "$hist_data" ] && printf "History is empty!\n" >&2 && return 1;
+ 		#removes duplicate values from $history_data
+-		videos_data=$(printf "%s" "$hist_data" | uniq )
++		videos_data=$(printf "%s" "$hist_data" | @uniq@ )
+ 		[ "$sort_videos_data" -eq 1 ] && videos_data="$(printf "%s" "$videos_data"  | sort_video_data_fn)"
+ 	else
+ 		printf "History is not enabled. Please enable it to use this option (-H).\n" >&2;
+@@ -1177,10 +1177,10 @@ get_search_history () {
+ 	if [ "$enable_search_hist" -eq 1 ]; then
+ 		[ -e "$search_history_file" ] || : > "$search_history_file"
+ 		#gets history data in reverse order (makes it most recent to least recent)
+-		hist_data=$( sed '1!G; h; $!d' "$search_history_file" )
++		hist_data=$( @sed@ '1!G; h; $!d' "$search_history_file" )
+ 		[ -z "$hist_data" ] && printf "Search history is empty!\n" >&2 && return 1;
+ 		#removes duplicate values from $history_data
+-		search_history=$(printf "%s" "$hist_data" | uniq )
++		search_history=$(printf "%s" "$hist_data" | @uniq@ )
+ 	else
+ 		printf "Search history is not enabled. Please enable it to use this option (-q).\n" >&2;
+ 		exit 1;
+@@ -1190,7 +1190,7 @@ get_search_history () {
+ 
+ set_search_history () {
+     [ -z "$search_query" ] && return
+-    [ $enable_search_hist -eq 1 ] && printf "%s\t%s\n" "$(date '+%Y-%m-%d %H:%M:%S')" "$search_query" >> "$search_history_file" ;
++    [ $enable_search_hist -eq 1 ] && printf "%s\t%s\n" "$(@date@ '+%Y-%m-%d %H:%M:%S')" "$search_query" >> "$search_history_file" ;
+ }
+ 
+ search_history_menu () {
+@@ -1200,15 +1200,15 @@ search_history_menu () {
+     #when using an external menu, the search history will be done there
+         choice=$( printf "%s\n" "$search_history" | eval "$external_menu" )
+     else
+-        choice="$( printf "%s\n" "$search_history" | fzf --prompt="$search_history_prompt" --print-query --no-multi -d '\t' --with-nth=2.. --expect='alt-enter' --bind='tab:replace-query' )"
++        choice="$( printf "%s\n" "$search_history" | @fzf@ --prompt="$search_history_prompt" --print-query --no-multi -d '\t' --with-nth=2.. --expect='alt-enter' --bind='tab:replace-query' )"
+     fi
+ 
+     # first line is the fzf query (what the user types in fzf)
+     # second line is the fzf --expect key pressed
+     # third line is the search_history selection made
+-    query="$( printf "%s" "$choice" | sed -n '1p' )"
+-    key="$( printf "%s" "$choice" | sed -n '2p' )"
+-    selection="$( printf "%s" "$choice" | sed -n '3p' )"
++    query="$( printf "%s" "$choice" | @sed@ -n '1p' )"
++    key="$( printf "%s" "$choice" | @sed@ -n '2p' )"
++    selection="$( printf "%s" "$choice" | @sed@ -n '3p' )"
+ 
+     # if no search history selection has been made
+     # and the user typed a query, use that instead
+@@ -1225,7 +1225,7 @@ search_history_menu () {
+             search_query="$query"
+             return;;
+     esac
+-    search_query="$( printf "%s" "$selection" | awk -F'\t' '{printf "%s", $NF}' )"
++    search_query="$( printf "%s" "$selection" | @awk@ -F'\t' '{printf "%s", $NF}' )"
+ }
+ 
+ ! function_exists "send_select_video_notif" && send_select_video_notif () {
+@@ -1244,13 +1244,13 @@ search_history_menu () {
+ 
+ 	#if downloading, say Downloading not currently playing
+ 	[ $is_download -eq 1 ] && title="Downloading" || title="Currently playing"
+-	notify-send "$title" "$message" -i "$video_thumb"
++	@notify-send@ "$title" "$message" -i "$video_thumb"
+ 
+ 	unset message video_thumb title
+ }
+ 
+ send_notify () {
+-	videos_selected_count=$(printf "%s\n" "$*" | wc -l)
++	videos_selected_count=$(printf "%s\n" "$*" | @wc@ -l)
+ 	while IFS=$tab_space read -r video_title video_channel video_views video_duration video_date video_shorturl; do
+ 	    send_select_video_notif
+ 	done << EOF
+@@ -1284,14 +1284,14 @@ if ! function_exists "data_sort_key"; then
+ 	sort_by="${5#|}"
+ 	sort_by="${sort_by#Streamed}"
+ 	#print the data that should be sorted by
+-	printf "%d" "$(date -d "${sort_by}" '+%s')"
++	printf "%d" "$(@date@ -d "${sort_by}" '+%s')"
+ 	unset sort_by
+     }
+ fi
+ #the function to use for sorting
+ if ! function_exists "data_sort_fn"; then
+     data_sort_fn () {
+-	sort -nr
++	@sort@ -nr
+     }
+ fi
+ sort_video_data_fn () {
+@@ -1300,7 +1300,7 @@ sort_video_data_fn () {
+ 		IFS="$tab_space"
+ 		#run the key function to get the value to sort by
+ 		printf "%s\t%s\n" "$(data_sort_key $line)" "$line"
+-	done | data_sort_fn | cut -f2-
++	done | data_sort_fn | @cut@ -f2-
+ 	unset IFS line 
+ }
+ 
+@@ -1314,19 +1314,19 @@ scrape_subscriptions () {
+ 	while IFS= read -r url; do
+ 		scrape_channel "$url" &
+ 	done <<-EOF
+-	$( sed \
++	$( @sed@ \
+ 	-e "s/#.*//" \
+ 	-e "/^[[:space:]]*$/d" \
+ 	-e "s/[[:space:]]*//g" \
+ 	"$subscriptions_file")
+ 	EOF
+ 	wait
+-	videos_json="$(cat "$tmp_video_json_file")"
++	videos_json="$(@cat@ "$tmp_video_json_file")"
+ 	export videos_json
+ 	if [ $sort_videos_data -eq 1 ]; then 
+ 		videos_data=$(sort_video_data_fn < "$tmp_video_data_file")
+ 	else
+-		videos_data=$(cat "$tmp_video_data_file")
++		videos_data=$(@cat@ "$tmp_video_data_file")
+ 	fi
+ }
+ 
+@@ -1346,11 +1346,11 @@ create_subs () {
+     : > "$config_dir/subscriptions"
+ 
+     # check how many subscriptions there are in the file
+-    sublength=$( jq '. | length' < "$yt_sub_import_file" )
++    sublength=$( @jq@ '. | length' < "$yt_sub_import_file" )
+ 
+-    for i in $(seq $((sublength - 1))); do
+-        channelInfo=$(jq --argjson index ${i} '[ "https://www.youtube.com/channel/" + .[$index].snippet.resourceId.channelId + "/videos", "#" + .[$index].snippet.title ]' < "$yt_sub_import_file")
+-	printf "%s\n" "$(printf "%s" "$channelInfo" | tr -d '[]"\n,')" >> "$subscriptions_file"
++    for i in $(@seq@ $((sublength - 1))); do
++        channelInfo=$(@jq@ --argjson index ${i} '[ "https://www.youtube.com/channel/" + .[$index].snippet.resourceId.channelId + "/videos", "#" + .[$index].snippet.title ]' < "$yt_sub_import_file")
++	printf "%s\n" "$(printf "%s" "$channelInfo" | @tr@ -d '[]"\n,')" >> "$subscriptions_file"
+     done
+     exit
+ }
+@@ -1367,10 +1367,10 @@ verify_thumb_disp_method () {
+ 
+ #sort -R is not posix
+ posix_shuf () {
+-    awk -F '\n' '
++    @awk@ -F '\n' '
+ 	BEGIN {srand()} #set the random seed at the start
+ 	{print rand() " " $0} #prepend a random number for each line' |\
+-    sort | sed -E 's/[^ ]* //'
++    @sort@ | @sed@ -E 's/[^ ]* //'
+     #sort by the random numbers, remove the random number
+ }
+ 
+@@ -1486,8 +1486,8 @@ parse_opt () {
+ 			exit ;;
+ 		version)
+ 			printf "\033[1mytfzf:\033[0m %s\n" "$YTFZF_VERSION"
+-			printf "\033[1myoutube-dl:\033[0m %s\n" "$(youtube-dl --version)"
+-			command -v "fzf" 1>/dev/null && printf "\033[1mfzf:\033[0m %s\n" "$(fzf --version)"
++			printf "\033[1myoutube-dl:\033[0m %s\n" "$(@youtube-dl@ --version)"
++			command -v "@fzf@" 1>/dev/null && printf "\033[1mfzf:\033[0m %s\n" "$(@fzf@ --version)"
+ 			exit ;;
+ 
+ 		subt)
+@@ -1559,19 +1559,19 @@ done
+ shift $((OPTIND-1))
+ 
+ #only apply to ext_menu since they dont have a terminal to print to
+-[ $is_ext_menu -eq 1 ] && command -v notify-send 1>/dev/null 2>&1 && ext_menu_notifs=1 || ext_menu_notifs=0
++[ $is_ext_menu -eq 1 ] && command -v @notify-send@ 1>/dev/null 2>&1 && ext_menu_notifs=1 || ext_menu_notifs=0
+ 
+ #used for thumbnail previews in ueberzug
+ if [ $is_ext_menu -eq 0 ]; then
+-	export TTY_LINES=$(tput lines)
+- 	export TTY_COLS=$(tput cols)
++	export TTY_LINES=$(@tput@ lines)
++	export TTY_COLS=$(@tput@ cols)
+ fi
+ 
+ #if both are true, it defaults to using fzf, and if fzf isnt installed it will throw an error
+ #so print this error instead and set $show_thumbnails to 0
+ if [ $is_ext_menu -eq 1 ] && [ $show_thumbnails -eq 1 ]; then
+ 	[ $ext_menu_notifs -eq 1 ] &&\
+-	    notify-send "warning" "Currently thumbnails do not work in external menus" ||\
++	    @notify-send@ "warning" "Currently thumbnails do not work in external menus" ||\
+ 	    printf "\033[33mWARNING: Currently thumbnails do not work in external menus\033[0m\n" >&2
+ 	show_thumbnails=0
+ fi
+-- 
+2.32.0
+
diff --git a/gnu/packages/patches/ytfzf-updates.patch b/gnu/packages/patches/ytfzf-updates.patch
new file mode 100644
index 0000000000..1790b7a238
--- /dev/null
+++ b/gnu/packages/patches/ytfzf-updates.patch
@@ -0,0 +1,44 @@
+From 75bf4f584866a013d5618ea6be19e97a8196d63e Mon Sep 17 00:00:00 2001
+From: Raghav Gururajan <[email-masked]>
+Date: Mon, 5 Jul 2021 06:47:38 -0400
+Subject: [PATCH 2/2] Disable updates within the application.
+
+Patch the code responsible for self-updating the application.
+
+Co-authored-by: jgart <[email-masked]>
+---
+ ytfzf | 18 ++----------------
+ 1 file changed, 2 insertions(+), 16 deletions(-)
+
+diff --git a/ytfzf b/ytfzf
+index 0a2c372..845e8e9 100755
+--- a/ytfzf
++++ b/ytfzf
+@@ -1260,22 +1260,8 @@ EOF
+ }
+ 
+ update_ytfzf () {
+-	branch="$1"
+-	updatefile="/tmp/ytfzf-update"
+-	curl -L "https://raw.githubusercontent.com/pystardust/ytfzf/$branch/ytfzf" -o "$updatefile"
+-
+-	if sed -n '1p' < "$updatefile" | grep -q '#!/bin/sh'; then
+-		chmod 755 "$updatefile"
+-		[ "$(uname)" = "Darwin" ] && prefix="/usr/local/bin" || prefix="/usr/bin"
+-		function_exists "sudo" && doasroot="sudo" || doasroot="doas"
+-		$doasroot cp "$updatefile" "$prefix/ytfzf"
+-		unset prefix doasroot
+-	else
+-		printf "%bFailed to update ytfzf. Try again later.%b" "$c_red" "$c_reset"
+-	fi
+-
+-	rm "$updatefile"
+-	exit 0
++       printf "%bUpdates have to be installed with Guix.%b\n" "$c_red" "$c_reset"
++       exit 1
+ }
+ 
+ #gives a value to sort by (this will give the unix time the video was uploaded)
+-- 
+2.32.0
+
-- 
2.32.0