Shell scripts minimizing machine time, maximizing tao time.

git clone git://watertao.xyz/programs/tao_shells.git

commit 2fac695147d53b6890d1d88721c3b8c26557cc4a
Author: Jeff <dev@watertao.xyz>
Date:   Wed, 25 Feb 2026 12:11:10 -0800

Init

Diffstat:
AREADME | 341+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atao_bluetooth_connect.sh | 31+++++++++++++++++++++++++++++++
Atao_copy.sh | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Atao_notes.sh | 48++++++++++++++++++++++++++++++++++++++++++++++++
Atao_pactl_setsink.sh | 41+++++++++++++++++++++++++++++++++++++++++
Atao_url.sh | 258+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atao_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 +