commit 2fac695147d53b6890d1d88721c3b8c26557cc4a
Author: Jeff <dev@watertao.xyz>
Date: Wed, 25 Feb 2026 12:11:10 -0800
Init
Diffstat:
| A | README | | | 341 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | tao_bluetooth_connect.sh | | | 31 | +++++++++++++++++++++++++++++++ |
| A | tao_copy.sh | | | 51 | +++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | tao_notes.sh | | | 48 | ++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | tao_pactl_setsink.sh | | | 41 | +++++++++++++++++++++++++++++++++++++++++ |
| A | tao_url.sh | | | 258 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | tao_youtube_query.sh | | | 167 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
7 files changed, 937 insertions(+), 0 deletions(-)
diff --git a/README b/README
@@ -0,0 +1,341 @@
+tao_shells
+----------
+Text user interface(TUI) for everyday computer/device tasks.
+
+
+Usage
+-----
+
+ $ tao_bluetooth_connect # Connect to bt device
+ $ tao_copy.sh $1 # Yank $1
+ $ tao_copy.sh - # Yank stdin
+ $ tao_notes.sh # Notes
+ $ tao_pactl_setsink.sh # Set audio output device
+ $ tao_url.sh # Open url
+ $ tao_url.sh -q # Internet query
+ $ tao_url.sh -y # Download and play youtube video
+ $ tao_youtube_query.sh # Youtube videos from listed channels
+
+
+Requirements
+------------
+- your-favorite-terminal-emulator
+- your-favorite-terminal-text-editor
+- your-favorite-cli-browser
+- your-favorite-gui-browser
+- dmenu (or bemenu/rofi)
+- mpv
+- yt-dlp
+- wget
+
+
+Description
+-----------
+Shell scripts minimizing machine time, maximizing tao time.
+
+This is for the CLI and TUI folks in the crowd. If you are already a
+unix-based/linux user and live in the GUI, I encourage you to explore
+the command line and become familiar with the terminal environment. To
+get started, using a terminal text editor (e.g. vim) is a great way to
+get your hands dirty. You'll be searching for files cli style and
+editing them all in the terminal. Maybe start a journal this way.
+
+The tao_url.sh is a core utility that has undergone maybe 6 rewrites. I learn
+something new and then all of a sudden, everything needs to be rewritten. And I
+do enjoy the process. It is a hobby of mine. And I feel these scripts are in a
+good enough place to be shared. So here we are. Welcome the tao shells.
+
+The purpose of these programs, particularly tao_url, is to minimize distraction
+in our lives. The internet is a massive distraction downpour. The tao_url.sh is
+not an umbrella, it removes you from the storm and keeps you above it, as much
+as it can. The idea is to pull things out of the storm, into your the light of
+your home, for intentional purposes. tao_url.sh is there to help users take
+control and hone their relationship with the internet. So how does it work. The
+primary interface is suckless.org's wonderful dmenu. If you are an X11 user,
+please install dmenu ( See dmenu below ). If you are running a Wayland
+environment, you'll want to install bemenu. Rofi will also work. But one of
+the three are required to use the tao shells. How each tao shell program works
+is outlined below.
+
+
+Environment Variables
+---------------------
+A word regarding env vars first. Although not required, you may set the
+following to the programs you run on your local system:
+- TERMINAL
+- DMENU
+- EDITOR
+
+For the unlettered, please refer to your shell's man page for further
+reading on environment variables. These can also be set in tao_url.conf
+(See Files below).
+
+tao shells will try to discover each for the following programs:
+- TERMINAL=st,urxvt,xterm
+- DMENU=dmenu,rofi,bemenu
+
+
+tao_url.sh
+----------
+
+There is a lot going on here with such a simple utility, so get a cup
+coffee or tea or water, get your cozy's on, and let's get into it.
+
+First, the flow of what happens when this program runs.
+
+
+### Url mode:
+
+01
+You are prompted to enter a url. The dmenu list will be populated with
+history and bookmarks below the prompt. As you type, the fuzzy find
+reduces the list accordingly. You can quickly find history urls and
+bookmarks this way, or simply enter a fresh url to do something with.
+And because dmenu is amazing, it's fast.
+
+02
+After url selection, you are prompted with a list of programs. How will
+you be opening or using this url? Web browsers of course are a natural
+method. Defaults are qutebrowser, firefox, w3m, and links (See Text
+Browsers below on why w3m and links are important). You can also
+bookmark or yank(copy) the url from this menu. More on those tasks
+below. If the url is an image file, you can run by default nsxiv to view
+it. If an a/v url, mpv is there as an option. With images and video
+urls, by selecting their respective openers, you'll be asked first if
+you'd like to download the file first. In most case, unless it's a/v,
+downloading first is and excellent idea. More on that later.
+
+03
+If you're opening the url with a browser, you'll be off and running. If
+downloading first, you'll see a terminal open running wget to download
+the file, then once completed, the respective opener will launch and
+you'll be greeted with the content requested.
+
+
+### Query mode:
+
+You are afforded the same steps as above, with a few important
+differences.
+
+01
+You are prompted initally for query/search terms instead of a url
+address. The history of your searches will be at your disposal as you
+type.
+
+02
+Once your query is ready, you can select any browser to open it, and the
+default duckduckgo will provide the results. If it is a youtube video,
+you can ytdlp/mpv option is there to download first, then mpv play the
+video locally.
+
+
+### Youtube:
+
+See Youtube Videos below.
+
+
+### Local mode:
+
+I'd avoid using this for now. It's well overdue for some tuning. I
+never use it anymore, I don't recommend it, and as such may be
+removed entirely in the unforseeable future.
+
+
+So why is this important. Why inject all these questions and steps into
+simply opening a url. Please see Ethos below.
+
+
+dmenu
+-----
+I will be writing more about dmenu in the future, quite likely when I've
+uploaded my dmenu configurations to the git server here, maybe never,
+who knows. For now my recommendation is to first download it from your
+distro's repo and explore it's usage a bit. Once your hooked, you'll
+want to customize the aesthetic, in which case I recommend cloning the
+git repo from suckless.org along with relevant patches, get all that
+building without error, sort out your config.def.h, and you'll be a
+happier dmenu user on the other side.
+
+
+Text Browsers
+-------------
+I will save the ethos of text browsers for the Ethos section below.
+Briefly, text browsing is a valuable and important step in taking
+control of your relationship with the internet. Text browsing is exactly
+as it sounds. A web page is requested from its server, and the content
+is returned to your client, as usual. The only difference is your client
+runs in a terminal window, and that's a big difference. Javascript is
+supported in some text browsers, but style sheets and images are all
+stripped. Image placeholders are often used for awareness of the
+material and in the case you wish to view it, options are available for
+media consumption.
+
+In using a text browser, you laser focus your usage of content retrieved
+from the internet. More on that in Ethos below. The learning curve and
+comfort acclimation are very real here. Out of the gates, parsing lines
+of text visually is an entirely different and an uncomfortable
+experience. It was worth the struggle for me. It may be for you too. It
+may not. Whatever it is. It's ok.
+
+
+Youtube Videos
+--------------
+For the ethos portion of this discussion, see Ethos. This section
+focuses on the usage of youtube content using tao_url.sh and
+tao_youtube_query.sh.
+
+
+### Download and view:
+
+Running 'tao_url.sh -r', type or paste the youtube video link, hit
+Enter, then you are prompted as usual with a list of opener options.
+Select 'yt/mpv' to download first, then play locally using mpv.
+
+ tao_url.sh -r; [enter link]; yt/mpv;
+
+
+### Streaming video:
+
+Same process as 'Download and view' above, except instead of
+'yt/mpv', simply open with 'mpv' instead. You'll be prompted to
+'Download first?', whereupon you'll answer no, and mpv will begin
+streaming the video.
+
+ tao_url.sh -r; [enter link]; mpv; n;
+
+
+### Search:
+
+tao_url.sh -q as usual for internet searching, including youtube.
+After entering/selecting keywords to search, in the opener prompt,
+select 'yt search'. You are then presented with a list of youtube
+videos. Once a video is selected, you'll be prompted with opener
+options, 'yt/mpv' to download then view, or 'mpv' for streaming.
+
+ tao_url.sh -q; [enter search words]; yt search;
+
+
+### Channel videos:
+
+Same process as above for download/view/streaming, except for the
+url, you enter a youtube channel's url, then select either of the
+two 'yt channel...' options. The first limits the video list to 50
+for speed of service purposes. The other gets fetches everything,
+takes a little longer, but worth it if you're digging into history.
+
+ tao_url.sh -r; [enter yt channel address]; yt channel; [select video]; ...
+
+
+### Fetching latest videos from a list of channels:
+
+With a populated tao_channel_fetch_latest.sites config file, running
+tao_youtube_query.sh fetches a list of latest videos from every
+listed channel, sorts in date order, and offers this list for your
+perusal and selection, dmenu style. As many videos as you like can
+be launched using yt/mpv opener option, as each video will download
+in its own terminal window and play automatically once respective
+download completes. A nice way to catch up very quickly with
+channels of interest.
+
+ tao_youtube_query.sh;
+
+
+### Recommended keybinds for your window manager:
+
+ tao_url.sh -r
+ tao_url.sh -q
+ tao_youtube_query.sh
+
+
+Files
+-----
+```
+~/.local/share/tao/
+ url/
+ bookmark
+ history
+ query
+
+~/.config/tao/
+ tao_channel_fetch_latest.sites
+ tao_dmenu.conf
+ tao_openers.conf
+ tao_url.conf
+
+tao_url.conf optional variables:
+ TAO_QUERY_ENG
+ TAO_EXEC_IN_TERM
+ TAO_DL_THEN_OPEN
+```
+
+
+Ethos: Computers and our Relationship with the Internet
+-------------------------------------------------------
+What's the point of all of this? I happen to be a shell scripting
+hobbyist. So crafting these ui scripts is actually enjoyable. That's
+really important. I live by few rules. One of them is to die smiling, at
+any point. Life takes its turns and it's not always easy to say that. I
+know I need to make moves if it is untrue. And so my engagement shifts.
+This is the wildness of wind in a creature that normally strongly
+associates with the stillness of trees.
+
+Crafting a user interface layer between me and the system, including the
+internet not only keeps me above the mess but allows me to use a system
+in an aesthetic that very much resonates, as so much of one's self
+reflects in the end product. That's an element, and also important.
+
+So there's the personal gain for me. But what about beyond that? Is
+there any gain for you or I to actually use these things?
+
+The full story of what's happening in our devices every time we use
+them, actually even while they sit idly in our pockets, is a story
+extraordinarily outside the scope of this writing. So we will focus for
+a moment only on the internet. Spoiler and tldr;, the internet sucks.
+
+Something I appreciate deeply about suckless.org is their name. The
+acknowledgement is inherent. Software sucks. All of it. They attempt to
+provide software that merely sucks less. This is especially true
+regarding the internet. Web browsers are terrible. All of them. The best
+can be found in text browsers. I love every one of them, even with all
+their sucktitude. So lets speak softly for a moment on the merits and
+ethos of using text browsers instead of gui.
+
+The internet lure is strong. It doesn't take much to keep a user simply
+connected to and aimlessly using the internet. A web page with nicely
+aligned and admirably spaced, sized and fonted text, featuring a simple
+yet pleasant color palette is all it takes. We are attracted to design.
+Design is art and art is emotional. I'm not talking about crying over
+page layout, I speaking to that thing that happens in us when something
+feels good. Even subtly so. When information becomes entertaining, we
+are roughly one click away from falling deeper into the digital world of
+our devices. Pure distraction awaits. The astronomical level of life
+distraction is merely one problem among many. The social, physical,
+religious and political... in a word, mass cultural effect of the
+internet alone is something else entirely. I say all of this not to
+completely overshadow any benefit that may be gleaned from this monster.
+Communication is critical to understanding the world of humanity at the
+very least. So to harness the communicative power of interconnected
+devices simultaneously mitigating the damage is something I attribute
+likely too much thought too entirely. But here we are. I'm going to cut
+off all these half thoughts to end what is really only a README file for
+some shell scripts.
+
+The bottom line is to maximize our time alive, with life itself. Our
+actual, analog, very real bodies, minds, souls and hearts. Our own, and
+the others in our company. The internet is intended to be a trustless
+system, and we ought to use it as such, and use it far far less. Less
+endless scrolling, "screen time" of digital consumption. Less
+surveillance of our lives by strangers we do not know and ought not
+trust. The internet has it's uses, and the tao shells exist to leverage
+the positives and diminish the spell. These tools and so many others
+alike in the wild are here to help humanity return to humanity.
+
+
+Notes
+-----
+Every idea introduced in this file can be grossly expanded upon, and
+most certainly has been done so by many others. These are mere notes to
+a handful of utilities for the unix/linux user. There exist other tao
+shells for a myriad of other tasks, and when the time comes that they
+find comfort within themselves, they will walk out the front door as
+these shells have done and join the world of open source.
diff --git a/tao_bluetooth_connect.sh b/tao_bluetooth_connect.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+cmdf(){ command -v $1 >/dev/null 2>&1; }
+! cmdf "bluetoothctl" && \
+ printf "Please install bluetoothctl to use me.\n" && exit 1
+
+# dmenu command
+if [ -z "$DMENU" ]
+then
+ a="dmenu sxmo_dmenu.sh bemenu rofi"
+ for i in $a; do cmdf "$i" && export DMENU="$i" && break; done
+fi
+
+# optional configs
+a="$XDG_CONFIG_HOME/tao/tao_dmenu.conf" && [ -f "$a" ] && . "$a"
+export DMENU_OPTS="${DMENU_OPTS:-""}"
+
+a=$(bluetoothctl devices | awk '{printf("%-10s %s\n", $3, $2)}' | \
+ $DMENU -i $DMENU_OPTS -p "[ connect to bluetooth device ]")
+
+[ -z "$a" ] && exit 0
+
+sleep 1
+a="${a##* }"
+printf "Connecting to %s\n" "$a"
+/usr/bin/bluetoothctl -t 1 discoverable on
+/usr/bin/bluetoothctl -t 10 --monitor scan on
+/usr/bin/bluetoothctl pair $a
+sleep 2
+/usr/bin/bluetoothctl trust $a
+sleep 2
+/usr/bin/bluetoothctl connect $a
diff --git a/tao_copy.sh b/tao_copy.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+# Simply yank/copy situation
+
+nofb="${TAO_NOFB:-""}"
+dn=/dev/null
+
+cmdf(){ command -v $1 >$dn 2>&1; }
+
+# dmenu command
+if [ -z "$DMENU" ]; then
+ a="dmenu sxmo_dmenu.sh bemenu rofi"
+ for i in $a; do cmdf "$i" && DMENU="$i" && break; done
+fi
+
+cu(){ exit 0; }; trap cu INT
+
+dmm(){ [ "$nofb" != 1 ] && <$dn>$dn "$DMENU" -p "$1"; return 0; }
+
+nils()
+{
+ dmm "Nothing in pipe or parameter to yank." && cu
+}
+
+suc(){ dmm "Yanked: $a"; }
+
+prnt(){ printf "%s" "$a"; }
+
+# stdin or param
+[ "$1" = "-" ] && a=$(cat -) || a="$1"
+
+[ -z "$a" ] && nils
+
+if cmdf "xclip"
+then
+ prnt | xclip
+ prnt | xclip -sel c
+ suc
+
+elif cmdf "xsel"
+then
+ prnt | xsel -i
+ prnt | xsel -ib
+ suc
+
+elif cmdf "wl-copy"
+then
+ prnt | wl-copy
+ suc
+fi
+cu
diff --git a/tao_notes.sh b/tao_notes.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+# A lightning fast notes program
+# Requirements: dmenu and a terminal emulator
+
+# following config normally lives in included conf file,
+# but for the sake of simplicity in sharing these shell scripts
+# I included the relevant definitions here, dmenu and term
+
+cmdf(){ command -v "$1" >/dev/null 2>&1; }
+
+# dmenu command
+a="dmenu sxmo_dmenu.sh bemenu rofi"
+for i in $a; do cmdf "$i" && dmenu="$i" && break; done
+
+# term command
+a="st urxvt xterm sxmo_terminal.sh"
+for i in $a; do cmdf "$i" && term="$i" && break; done
+
+# dmenu config
+a="$XDG_CONFIG_HOME/tao/tao_dmenu.conf" && [ -f "$a" ] && . "$a"
+dmenu_opts="${dmenu_opts:-""}"
+
+cu(){ exit 1; }; trap cu INT
+
+d=$HOME/.local/share/tao/notes
+[ ! -d "$d" ] && mkdir -p "$d"
+
+notesel(){
+ ls -1 "$d" | \
+ "$dmenu" $dmenu_opts -p "Tao Notes" || return 1
+}
+
+fnote(){
+ a=$(notesel) && [ -n "$a" ] || return 1
+ printf "%s\n" "$a" | while IFS= read -r f; do
+ if [ "${f##*::}" = "r" ]; then
+ g="$d/${f%::r}"
+ [ -f "$g" ] && rm "$g"
+ return 0
+ else
+ "$term" "$EDITOR" "$d/$f"
+ return 1
+ fi
+ done && return 0 || return 1
+}
+
+while fnote; do :; done
diff --git a/tao_pactl_setsink.sh b/tao_pactl_setsink.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+# Set the output sink to an available device
+# Requires pulse audio, uses the pactl interface
+
+cmdf(){ command -v $1 >/dev/null 2>&1; }
+! cmdf "pactl" && \
+ printf "Please install pactl to use me.\n" && exit 1
+
+# dmenu command
+if [ -z "$DMENU" ]
+then
+ a="dmenu sxmo_dmenu.sh bemenu rofi"
+ for i in $a; do cmdf "$i" && export DMENU="$i" && break; done
+fi
+
+# optional configs
+a="$XDG_CONFIG_HOME/tao/tao_dmenu.conf" && [ -f "$a" ] && . "$a"
+export DMENU_OPTS="${DMENU_OPTS:-""}"
+
+a=$(pactl list sinks | \
+ awk '{
+ if (x==1){
+ if (/^\tState: RUNNING/){
+ state=">"
+ }
+ if (/^\tDescription/){
+ sub(/^\tDescription: /,"")
+ print state, $0, sink
+ x=0
+ }
+ }
+ if (/^Sink/){
+ x=1
+ sink=$2
+ state=" "
+ }}' | \
+ $DMENU -i $DMENU_OPTS -p "[ audio sink select ]")
+
+[ -n "$a" ] && \
+ pactl set-default-sink ${a##* #}
diff --git a/tao_url.sh b/tao_url.sh
@@ -0,0 +1,258 @@
+#!/bin/sh
+
+# A core component of the url tao shells.
+# See README
+
+cu(){ e="${1:-0}"; rm "$t"; exit "$e"; }
+trap cu INT
+
+export PROGDIR="$(cd -- "$(dirname -- "$0")" && pwd)"
+
+dn=/dev/null
+cmdf(){ command -v $1 >$dn 2>&1; }
+
+# dmenu command
+if [ -z "$DMENU" ]
+then
+ a="dmenu sxmo_dmenu.sh bemenu rofi"
+ for i in $a; do cmdf "$i" && export DMENU="$i" && break; done
+fi
+dm="$DMENU"
+
+# term command
+if [ -z "$TERMINAL" ]
+then
+ a="st urxvt xterm sxmo_terminal.sh"
+ for i in $a; do cmdf "$i" && export TERMINAL="$i" && break; done
+fi
+trm="$TERMINAL"
+
+# optional configs
+a="$XDG_CONFIG_HOME/tao/tao_dmenu.conf" && [ -f "$a" ] && . "$a"
+export DMENU_OPTS="${DMENU_OPTS:-""}"
+dmo="-i $DMENU_OPTS"
+
+a="$XDG_CONFIG_HOME/tao/tao_url.conf" && [ -f "$a" ] && . "$a"
+ofile="$XDG_CONFIG_HOME/tao/tao_openers.conf"
+TAO_QUERY_ENG="${TAO_QUERY_ENG:-"https://ddg.gg?q="}"
+TAO_LOCAL_DIRS="${TAO_LOCAL_DIRS:-"$(printf "%s\n" "$HOME")"}"
+TAO_EXEC_IN_TERM="${TAO_EXEC_IN_TERM:-"w3m links mpv"}"
+TAO_DL_THEN_OPEN="${TAO_DL_THEN_OPEN:-"nsxiv mpv zathura"}"
+
+# File types: Local(1)(default) Remote(2) Query(3)
+ft=2
+cdir="$XDG_DATA_HOME/tao/url"
+qfile="${cdir}/query"
+bfile="${cdir}/bookmark"
+hfile="${cdir}/history"
+w3mh="$HOME/.w3m/history"
+noterm=0
+
+mk_ofile()
+{
+cat <<EOF >"$ofile"
+qutebrowser
+w3m
+firefox
+links
+surf
+ytdlp/mpv
+tao_youtube_query.sh -c%%yt channel (50)
+tao_youtube_query.sh -c -a%%yt channel (all)
+tao_youtube_query.sh -q%%yt search
+tao_copy.sh%%yank
+mpv --msg-level=all=status,ffmpeg/video=error%%mpv
+zathura
+nsxiv
+bookmark
+EOF
+}
+
+[ ! -d "$cdir" ] && mkdir -p "$cdir" && touch "$qfile" "$bfile" "$hfile"
+[ ! -f "$w3mh" ] && w3mh=$dn
+
+t="$(mktemp)"
+
+# Options
+usage()
+{
+ printf "%s\n" "Usage: tao_file [OPTION] [FILE ...]" "" "Options:"
+ printf "\t-%s\t%s\n" "l" "local file" "r" "remote file" "q" "query" "h" "help"
+ exit 0
+}
+
+prnt(){ printf "%s\n" "$1"; }
+
+dl_then_view()
+{
+ dmenu_yn "[ Download then view? ]" && return 0
+
+ x="$(mktemp -d)"; [ ! -d "$x" ] && cu
+ "$trm" wget --user-agent=Firefox "$u" -P "$x"
+ "$trm" $p "$x"/* 2>$dn
+ dmenu_yn "[ Remove tmp files: $(ls -1 "$x"/) ? y/n ]" && \
+ "$trm" -d "$x" || rm -r "$x"
+ cu
+}
+
+dmenu_for_file()
+{
+ [ $ft -eq 2 ] && input_remote && return 0
+ [ $ft -eq 3 ] && input_query && return 0
+ input_local && return 0
+ return 1
+}
+
+dmenu_yn() { [ "$(printf "y\nn" | "$dm" $dmo -p "${1:-"[]"}")" = "n" ]; }
+
+bookmark()
+{
+ a=$(prnt "$1" | $dm $dmo -p "[ Add Bookmark url + tags ]")
+
+ if <"$bfile" grep -Fqix "$a"; then
+ <$dn "$dm" $dmo -p "[ Bookmark already exists: $a ]"
+ else
+ prnt "$a" >>"$bfile" && \
+ <$dn "$dm" $dmo -p "[ Bookmark success: $a ]"
+ fi
+ return 0
+}
+
+file_action()
+{
+ u="$1"; [ -z "$ft" ] || [ -z "$u" ] && cu 1
+
+ if [ $ft -ne 1 ]
+ then
+ p=$(<$ofile sed 's/.*\%\%//' | "$dm" $dmo -p "[ $u ]")
+
+ [ -z "$p" ] && cu
+
+ # From ofile, translate opener name to command (if different)
+ p=$(prnt "$p" | sed 's/\([\/\#%]\)/\\\1/g')
+ p=$(<$ofile sed -n "/^$p$/{b a;}; /\%\%$p$/{b a;}; T; :a s/\%\%.*$//; p; q;")
+
+ prnt "$p"
+ # yt-dlp, special
+ if [ "$p" = "ytdlp/mpv" ]
+ then
+ # A serarate shell runs async so we aren't
+ # held up by the yt-dlp process.
+ if [ -z "$FETCHING_LATEST" ]
+ then
+ $trm -t "$p" tao_url.sh -y "$u" 1>$dn 2>&1
+ else
+ $trm -t "$p" tao_url.sh -y "$u" 1>$dn 2>&1 &
+ fi
+ cu
+ fi
+
+ # download-then-views first
+ prnt "$TAO_DL_THEN_OPEN" | grep -q "${p%% *}" && dl_then_view
+
+ # open term if needed
+ prnt "$TAO_EXEC_IN_TERM" | grep -q "${p%% *}" && [ $noterm -ne 1 ] && \
+ $trm $p "$u" && cu
+
+ [ "$p" != "tao_youtube_query.sh -q" ] && query_stage
+
+ # for all else just run it
+ $p "$u" && cu
+
+ else
+ case "$(prnt "$(file --mime-type -b "$u")" | tr "[:upper:]" "[:lower:]")" in
+ *webp|*jpeg|*jpg|*png|*gif|*svg ) p="$imager" ;;
+ *mp4|*m4a|*avi|*mpg|*ogg|*mp3|*flac|*flv|*matroska ) p="$trm $mpv" ;;
+ *txt|*md|*text ) p="$trm $EDITOR" ;;
+ *pdf ) p="$pdf" ;;
+ * ) p="$sbrowser" ;;
+ esac
+
+ $p "$u" 2>$dn &
+ fi
+}
+
+input_local()
+{
+ u="$(prnt "$TAO_LOCAL_DIRS" | \
+ xargs -r -i{} find {} -type f | \
+ "$dm" $dmo -p "[ local file ]")"
+ return 0
+}
+
+input_query()
+{
+ [ ! -f "$qfile" ] && touch "$qfile"
+ u="$(tac "$qfile" | \
+ "$dm" $dmo -p "[ query ]")" \
+ || cu 1
+ # Add query to query file if not already exists
+ grep -q -F "$u" "$qfile" \
+ || prnt "$u" >> "$qfile"
+ return 0
+}
+
+input_remote()
+{
+ # Dmenu for url to task
+ u="$(<"$bfile" sed 's/$/ bookmark/' | \
+ tac "$hfile" "$w3mh" - | \
+ sed '/^file:/d' | \
+ "$dm" $dmo -p "[ url ]")" \
+ || cu
+
+ # Clean up the history/bookmark link
+ u="$(prnt "$u" | \
+ sed -E 's/[^ ]+ +//g' | \
+ grep -E "https?:" \
+ || prnt "$u" | \
+ cut -d" " -f1 )"
+ return 0
+}
+
+query_stage()
+{
+ [ $ft -ne 3 ] && return 0
+ # Encode the search string (i.e. the rest of q). xxd was formerly used
+ # here, but xxd is part of vim packages on some systems, whereas od is
+ # ubiquitous. A search script that breaks if someone accidentally removes
+ # vim is stupid.
+ #u="${TAO_QUERY_ENG}$(printf "%s" "$u" | od -w1048 -t x1 -An | tr "[:space:]" "%20")"
+ u="${TAO_QUERY_ENG}$(printf "%s" "$u" | \
+ od -w1048 -t x1 -An | \
+ tr " " "%")"
+}
+
+ytdlp_mpv()
+{
+ t=$(mktemp -d)
+
+ yt-dlp --no-warnings \
+ -f 'bestvideo[ext=mp4][height<=720]+bestaudio[ext=m4a]/best[height<=720]' \
+ -o ${t}/'%(title)s-%(id)s.%(ext)s' "$u" && \
+ mpv "$t"/*
+
+ read -p "Remove tmp a/v file?" yn
+ [ "$yn" = "n" ] && "$trm" -d "$t" || rm -r "$t"
+
+ cu
+}
+
+while getopts "hlnqry" a; do
+ case $a in
+ h) usage ;; l) ft=1 ;; n) noterm=1 ;; q) ft=3 ;; r) ft=2 ;; y) ft=4 ;;
+ esac
+done
+
+shift $((OPTIND - 1))
+
+if [ $ft -eq 4 ]; then u="$1"; ytdlp_mpv; cu; fi
+
+# Chk for opener config file
+[ -f "$ofile" ] || mk_ofile
+
+# If files passed as arguments, open em up, else dmenu for url/file
+[ -n "$*" ] && \
+ for fn in "$@"; do file_action "$fn"; done || \
+ dmenu_for_file && [ -n "$u" ] && file_action "$u"
+cu
diff --git a/tao_youtube_query.sh b/tao_youtube_query.sh
@@ -0,0 +1,167 @@
+#!/bin/sh
+
+# Query youtube for videos.
+#
+# Default - fetch list of latest vids of channels listed in config file:
+# $XDG_CONFIG_HOME/tao/tao_channel_fetch_latest.sites
+#
+# -c "CHANNEL"
+# Fetch videos from CHANNEL
+#
+# -q "QUERY TERMS"
+# Search for yt videos for QUERY TERMS
+#
+# -a
+# Generate of all video results. Default returns 10.
+#
+# Requires dmenu, tao_url.sh, yt-dlp
+# Optionally uses fully functional ps (not busybox ver)
+
+typ="d"
+l=10
+pts_title="Fetching latest channel videos..."
+yt_prnt_opt="%(upload_date)s @ %(playlist_channel)s > %(title)s < ( %(view_count)s ) [ %(duration_string)s ] %(webpage_url)s"
+yt_url="-a -"
+
+export FETCHING_LATEST=1
+
+dn=/dev/null
+cmdf(){ command -v $1 >$dn 2>&1; }
+prnt(){ printf "%s\n" "$1"; }
+usepts=$( cmdf "ps" && ps -ax 2>$dn 1>&2 && printf "1" )
+
+# dmenu command
+if [ -z "$DMENU" ]
+then
+ a="dmenu sxmo_dmenu.sh bemenu rofi"
+ for i in $a; do cmdf "$i" && export DMENU="$i" && break; done
+fi
+dm="$DMENU"
+
+# term command (using TERMINAL not TERM for st reasons)
+if [ -z "$TERMINAL" ]
+then
+ a="st urxvt xterm sxmo_terminal.sh"
+ for i in $a; do cmdf "$i" && export TERMINAL="$i" && break; done
+fi
+
+# optional configs
+a="$XDG_CONFIG_HOME/tao/tao_dmenu.conf" && [ -f "$a" ] && . "$a"
+export DMENU_OPTS="${DMENU_OPTS:-""}"
+dmo="$DMENU_OPTS"
+
+# Safety first
+cu(){
+ rm -fr "$t" 2>$dn
+ if [ "$usepts" = "1" ]; then
+ ptsid="$(ps --no-headers -t pts/$ttyno -o pid)"
+ [ -n "$ptsid" ] && ( kill -9 "$ptsid" 2>$dn 1>&2; )
+ fi
+ exit 0
+}
+trap cu INT
+
+t=$(mktemp)
+
+dflt_chk()
+{
+ # All video sites live in the following file
+ yt_sites=$XDG_CONFIG_HOME/tao/tao_channel_fetch_latest.sites
+ if [ ! -s $yt_sites ]
+ then
+ <$dn "$dm" -i $dmo -p "<{ $yt_sites file empty. }>"
+ exit 0
+ fi
+}
+
+f_ytdlp()
+{
+ f_ytdlp_stdin | yt-dlp --flat-playlist -s \
+ --playlist-end $l \
+ --extractor-args "youtubetab:approximate_date" \
+ $prnt_tty \
+ --print "$yt_prnt_opt" \
+ -a - 2>$dn >> "$t"
+}
+
+f_ytdlp_stdin()
+{
+ if [ "$typ" = "q" ]; then
+ prnt "ytsearch$l:$q" && return 0
+ elif [ "$typ" = "c" ]; then
+ prnt "$q" && return 0
+ else
+ cat "$yt_sites" && return 0
+ fi
+}
+
+pts_open()
+{
+ prnt_tty=""
+ if [ "$usepts" = "1" ]
+ then
+ "$TERMINAL" -t "$pts_title $q" tail - 2>$dn &
+ a="$!"
+ sleep 0.2
+ ttyno=$(ps -ax | \
+ sed -n "/^ \?$a/ {
+ :start n
+ /pts/!{ b start }
+ s/[ 0-9a-z]\+\/\([0-9]\+\).*$/\1/p
+ }" | tr -d "\n")
+ prnt_tty="--print-to-file playlist:%(title)s /dev/pts/$ttyno"
+ fi
+}
+
+runthething()
+{
+ [ "$typ" = "d" ] && \
+ u=$(<$t grep -v '^N' | sort -r | \
+ "$dm" -i $dmo -p "[ Latest videos ]" 2>$dn; \
+ return 0) || \
+ u=$(<$t "$dm" -i $dmo -p "[ $yt_dm_title > $q ]")
+
+ [ -z "$u" ] && return 1
+
+ tao_url.sh -r "${u##* }" 2>$dn && return 0
+}
+
+a=; while getopts "acq" a
+do
+ case $a in
+ a)
+ l=10000 ;;
+ c)
+ typ="c"
+ l=100
+ pts_title="Fetching channel videos >"
+ yt_dm_title="channel videos"
+ yt_prnt_opt="%(upload_date)s > %(title)s < ( %(view_count)s ) [ %(duration_string)s ] %(webpage_url)s" ;;
+ q)
+ typ="q"
+ l=100
+ pts_title="YT query >"
+ yt_dm_title="query results"
+ yt_prnt_opt="%(upload_date)s @ %(channel)s > %(title)s < (%(view_count)s) [ %(duration_string)s ] %(webpage_url)s" ;;
+ esac
+done
+shift $(($OPTIND - 1))
+q="${1:-""}"
+
+[ "$typ" = "d" ] && dflt_chk
+
+# Open a pts for f_ytdlp monitoring
+pts_open
+
+# Query the tube
+f_ytdlp
+
+# If nothing retrieved, go for a walk
+[ -s $t ] || cu
+
+# Otherwise, lets see what we got
+while
+ runthething
+do :; done
+cu
+