summaryrefslogtreecommitdiff
path: root/home
diff options
context:
space:
mode:
Diffstat (limited to 'home')
-rw-r--r--home/wayland/pkgs/wayland-scripts/default.nix63
-rwxr-xr-xhome/wayland/pkgs/wayland-scripts/src/bin/damb300
-rwxr-xr-xhome/wayland/pkgs/wayland-scripts/src/bin/dbook313
-rwxr-xr-xhome/wayland/pkgs/wayland-scripts/src/bin/freezshot2
-rwxr-xr-xhome/wayland/pkgs/wayland-scripts/src/bin/pirowatch107
-rwxr-xr-xhome/wayland/pkgs/wayland-scripts/src/bin/tcsv160
-rwxr-xr-xhome/wayland/pkgs/wayland-scripts/src/bin/vpn19
7 files changed, 963 insertions, 1 deletions
diff --git a/home/wayland/pkgs/wayland-scripts/default.nix b/home/wayland/pkgs/wayland-scripts/default.nix
index e39907a..982453b 100644
--- a/home/wayland/pkgs/wayland-scripts/default.nix
+++ b/home/wayland/pkgs/wayland-scripts/default.nix
@@ -10,6 +10,16 @@
bemenu,
jq,
coreutils,
+ mpv,
+ util-linux,
+ gnugrep,
+ file,
+ wl-clipboard,
+ xdg-utils,
+ wtype,
+ curl,
+ tailscale,
+ bc,
}:
stdenvNoCC.mkDerivation {
@@ -56,6 +66,59 @@ stdenvNoCC.mkDerivation {
coreutils
]
}
+ wrapProgram $out/bin/damb \
+ --prefix PATH : ${
+ lib.makeBinPath [
+ libnotify
+ bemenu
+ mpv
+ util-linux
+ gnugrep
+ coreutils
+ file
+ ]
+ }
+ wrapProgram $out/bin/dbook \
+ --prefix PATH : ${
+ lib.makeBinPath [
+ libnotify
+ file
+ bemenu
+ coreutils
+ wl-clipboard
+ xdg-utils
+ wtype
+ ]
+ }
+ wrapProgram $out/bin/pirowatch \
+ --prefix PATH : ${
+ lib.makeBinPath [
+ libnotify
+ curl
+ bemenu
+ coreutils
+ gnugrep
+ # webtorrent
+ ]
+ }
+ wrapProgram $out/bin/tcsv \
+ --prefix PATH : ${
+ lib.makeBinPath [
+ libnotify
+ curl
+ bemenu
+ bc
+ # webtorrent
+ ]
+ }
+ wrapProgram $out/bin/vpn \
+ --prefix PATH : ${
+ lib.makeBinPath [
+ libnotify
+ gnugrep
+ tailscale
+ ]
+ }
'';
meta = {
diff --git a/home/wayland/pkgs/wayland-scripts/src/bin/damb b/home/wayland/pkgs/wayland-scripts/src/bin/damb
new file mode 100755
index 0000000..53d0cad
--- /dev/null
+++ b/home/wayland/pkgs/wayland-scripts/src/bin/damb
@@ -0,0 +1,300 @@
+#!/bin/sh
+
+damb_conf="${XDG_CONFIG_HOME:-$HOME/.config}/damb/damb.conf"
+damb_data="${XDG_DATA_HOME:-$HOME/.local/share}/damb"
+damb_pids="${XDG_RUNTIME_DIR:-${TMPDIR:-/tmp}}/damb.pids"
+damb_dlim="|"
+
+w_menu="bemenu"
+x_menu="dmenu"
+
+ico_damb="󰎆 "
+ico_locl="󱝟 "
+ico_ytbe=" "
+ico_sndc=" "
+ico_gurl="󰌹 "
+ico_what=" "
+
+usage()
+{
+ cat <<- EOF
+ Usage: damb [ command ] [ option ]
+ a bookmark manager using dmenu
+ Commands:
+ help show this help cruft
+ save <key> <value>, save a new key
+ rm <key>, remove a key
+
+ EOF
+}
+
+die()
+{
+ : "${1:?}"
+
+ command -v notify-send > /dev/null &&
+ notify-send "${ico_damb} damb" "$1"
+
+ printf "\033[31;1merr: %b\033[0m\n" "$1"
+ exit "${2:-1}"
+}
+
+dep_check()
+{
+ : "${1:?}"
+
+ for dep; do
+ command -v "$dep" 1>/dev/null ||
+ die "$dep not found, please install it" 127
+ done
+
+ unset dep
+}
+
+trim()
+{
+ : "${1:?}"
+
+ _trimstr="${1#"${1%%[![:space:]]*}"}"
+ _trimstr="${_trimstr%"${_trimstr##*[![:space:]]}"}"
+
+ echo "$_trimstr"
+}
+
+gen_ico()
+{
+ case "$1" in
+ https://www.youtube.com/*|https://youtu.be/*)
+ echo "$ico_ytbe" ;;
+ https://soundcloud.com/*)
+ echo "$ico_sndc" ;;
+ http*)
+ echo "$ico_gurl" ;;
+ /*)
+ echo "$ico_locl" ;;
+ *)
+ echo "$ico_what" ;;
+ esac
+}
+
+parse_keys()
+{
+ # usage parse_data [ getval <key> ]
+ line=
+ _key=
+ _value=
+
+ [ -s "$damb_conf" ] || return 1
+
+ while read -r line
+ do
+ [ -z "$line" ] && continue
+
+ _key="${line%%"$damb_dlim"*}"
+ _key="$(trim "$_key")"
+
+ case "$_key" in
+ \#*) continue
+ esac
+
+ if [ "$1" = "getval" ]; then
+ [ "$2" != "$_key" ] && continue
+
+ _value="${line##*"$damb_dlim"}"
+ _value="$(trim "$_value")"
+ echo "$_value"
+ return 0
+ else
+ echo "$_key"
+ fi
+ done < "$damb_conf"
+
+ unset _key _value
+ [ "$1" = "getval" ] && return 1
+}
+
+rm_key()
+{
+ # usage rm_data <key>
+ : "${1:?}"
+ cl=
+ line=
+ file=
+ value=
+ old_ifs="$IFS"
+
+ IFS=
+ while read -r line
+ do
+ cl="$line\n"
+
+ key="$(trim "${cl%%"$damb_dlim"*}")"
+ # catch match
+ if [ "$key" = "$1" ]; then
+ value="$(trim "${cl##*"$damb_dlim"}")"
+
+ # delete if saved
+ case "$value" in
+ "$damb_data"*) rm -f "$value"
+ esac
+ continue
+ fi
+
+ file="${file}${cl}"
+ done < "$damb_conf"
+
+ IFS="$old_ifs"
+ # shellcheck disable=SC2059
+ printf "$file" > "$damb_conf"
+ unset cl line file value old_ifs
+}
+
+verify_val()
+{
+ # verify_val <value>
+
+ case "$1" in
+ *"\n"*|*$damb_dlim*) return 1 ;;
+ esac
+
+ case "$(file --brief --dereference --mime-type "$1")" in
+ audio/*|video/*) ;;
+ *)
+ echo "$1" | grep -qxE '^(https?://)?[^/]*\.[A-Za-z0-9]*(/.*)?' ||
+ return 1
+ esac
+}
+
+write_kv()
+{
+ # verify_val <key> <value>
+ : "${1:?}"
+ : "${2:?}"
+
+ key="$(echo "$1" | tr -d "$damb_dlim")"
+ key="$(trim "$key")"
+ val="$(trim "$2")"
+
+ case "$key" in
+ [[:print:]]*) key="$(gen_ico "$val") ${key}" ;;
+ esac
+
+ parse_keys getval "$key" > /dev/null &&
+ die "keys must be unique"
+ verify_val "$val" ||
+ die "invalid: $val"
+
+ echo "${key:?} $damb_dlim $val" >> "$damb_conf"
+}
+
+kill_ambs()
+{
+ while read -r pid; do
+ kill -9 "$pid"
+ done < "$damb_pids"
+
+ rm "$damb_pids"
+}
+
+play_amb()
+{
+ : "${1:?}"
+
+ mpv --no-video --no-cache --no-resume-playback "$@" &
+ echo "$!" >> "$damb_pids"
+}
+
+set_menu()
+{
+ if [ -n "$WAYLAND_DISPLAY" ]; then
+ menu="$w_menu"
+ elif [ -n "$DISPLAY" ]; then
+ menu="$x_menu"
+ else
+ die "tty not supported"
+ fi
+
+ dep_check "$menu"
+}
+
+set_clip()
+{
+ if [ -n "$WAYLAND_DISPLAY" ]; then
+ dep_check "wl-paste"
+ _clip="$(wl-paste -n)"
+ elif [ -n "$DISPLAY" ]; then
+ dep_check "xclip"
+ _clip="$(xclip -o)"
+ fi
+
+ verify_val "$_clip"
+}
+
+gen_opts()
+{
+
+ [ -s "$damb_pids" ] && while read -r pid; do
+ if [ -d "/proc/${pid}" ]; then
+ echo " stop the ambiances"
+ break;
+ fi
+ done < "$damb_pids"
+
+ set_clip &&
+ echo "$(gen_ico "$_clip") $_clip (from clipboard)"
+
+ parse_keys
+}
+
+gen_menu()
+{
+ [ -s "$damb_conf" ] || die "empty, try damb save"
+ key="$(gen_opts | bemenu -l 25)" || return 1
+
+ case "$key" in
+ *"stop the ambiances")
+ kill_ambs ;;
+ *"from clipboard)")
+ set_clip
+ play_amb "$_clip" ;;
+ *)
+ play_amb --loop "$(parse_keys getval "$key")" ;;
+ esac
+}
+
+########
+# MAIN #
+########
+
+[ -d "$damb_data" ] || mkdir -p "$damb_data"
+[ -d "${damb_conf%/*}" ] || mkdir -p "${damb_conf%/*}"
+
+set_menu
+dep_check mpv
+
+case "$1" in
+rm)
+ key="$(parse_keys | "$menu" -l 25)" || exit 1
+ rm_key "$key"
+ ;;
+save)
+ [ "$#" -ne 3 ] &&
+ die "invalid usage, try damb help"
+
+ if [ -f "$3" ]; then
+ cp "$3" "$damb_data"
+ val="${damb_data}/${3##*/}"
+ fi
+
+ write_kv "$2" "${val:-$3}"
+ ;;
+"")
+ gen_menu
+ ;;
+help)
+ usage
+ ;;
+*)
+ die "invalid usage $*, try damb help"
+ ;;
+esac
diff --git a/home/wayland/pkgs/wayland-scripts/src/bin/dbook b/home/wayland/pkgs/wayland-scripts/src/bin/dbook
new file mode 100755
index 0000000..94523da
--- /dev/null
+++ b/home/wayland/pkgs/wayland-scripts/src/bin/dbook
@@ -0,0 +1,313 @@
+#!/bin/sh
+
+book_conf="${XDG_CONFIG_HOME:-$HOME/.config}/dbook/dbook.conf"
+book_data="${XDG_DATA_HOME:-$HOME/.local/share}/dbook"
+w_menu="bemenu"
+x_menu="dmenu"
+ico_dbk=" "
+ico_url="󰖟 "
+ico_doc=" "
+ico_pic=" "
+ico_vid=" "
+ico_mus="󰸪 "
+ico_fil=" "
+ico_txt=" "
+ico_dir=" "
+
+usage()
+{
+ cat <<- EOF
+ Usage: dbook [ command ] [ option ]
+ a bookmark manager using dmenu
+ Commands:
+ help show this help cruft
+ insert [ value [ key ] ], inset a new key
+ save [ value [ key ] ], inset but make a cp if it's a file
+ rm [ key ], delete a key
+ Options:
+ -t [ key ], type the vlaue
+ -c [ key ], copy the value to clipboard
+
+ EOF
+}
+
+note()
+{
+ : "${1:?}"
+
+ command -v notify-send > /dev/null &&
+ notify-send -- "${ico_dbk} dbook" "$1"
+}
+
+die()
+{
+ : "${1:?}"
+
+ note "$1"
+ printf "\033[31;1merr: %b\033[0m\n" "$1" 1>&2
+ exit "${2:-1}"
+}
+
+warn()
+{
+ : "${1:?}"
+
+ note "$1"
+ printf "\033[33;1merr: %b\033[0m\n" "$1" 1>&2
+}
+
+dep_check()
+{
+ : "${1:?}"
+
+ for dep; do
+ command -v "$dep" 1>/dev/null ||
+ die "$dep not found, please install it" 127
+ done
+
+ unset dep
+}
+
+trim()
+{
+ : "${1:?}"
+
+ _trimstr="${1#"${1%%[![:space:]]*}"}"
+ _trimstr="${_trimstr%"${_trimstr##*[![:space:]]}"}"
+
+ echo "$_trimstr"
+}
+
+load_icon()
+{
+ case "$(file --brief --dereference --mime-type "$1")" in
+ image/*) printf "%s" "$ico_pic" ;;
+ video/*) printf "%s" "$ico_vid" ;;
+ audio/*) printf "%s" "$ico_mus" ;;
+ text/*) printf "%s" "$ico_txt" ;;
+ inode/*) printf "%s" "$ico_dir" ;;
+ application/pdf) printf "%s" "$ico_doc" ;;
+
+ *'No such file or directory)')
+ if echo "$1" | grep -qxE '^(https?://)?[^/]*\.[A-Za-z0-9]*(/.*)?'; then
+ printf "%s" "$ico_url"
+ else
+ printf "%s" "$ico_fil"
+ fi
+ esac
+}
+
+parse_data()
+{
+ # usage parse_data [ getval <key> ]
+ line=
+ _key=
+ _value=
+
+ while read -r line
+ do
+ [ -z "$line" ] && continue
+
+ _key="${line%%|*}"
+ _key="$(trim "$_key")"
+
+ case "$_key" in
+ #*) continue
+ esac
+
+ if [ "$1" = "getval" ]; then
+ [ "$2" != "$_key" ] && continue
+
+ _value="${line##*|}"
+ _value="$(trim "$_value")"
+ echo "$_value"
+ return 0
+ else
+ echo "$_key"
+ fi
+ done < "$book_conf"
+
+ unset _key _value
+ [ "$1" = "getval" ] && return 1
+}
+
+rm_data()
+{
+ # usage rm_data <key>
+ : "${1:?}"
+ cl=
+ line=
+ file=
+ value=
+ old_ifs="$IFS"
+
+ IFS=
+ while read -r line
+ do
+ cl="$line\n"
+
+ key="$(trim "${cl%%|*}")"
+ # catch match
+ if [ "$key" = "$1" ]; then
+ value="$(trim "${cl##*|}")"
+
+ # delete if saved
+ case "$value" in
+ "$book_data"*) rm -f "$value"
+ esac
+ continue
+ fi
+
+ file="${file}${cl}"
+ done < "$book_conf"
+
+ IFS="$old_ifs"
+ # shellcheck disable=SC2059
+ printf "$file" > "$book_conf"
+ unset cl line file value old_ifs
+}
+
+clip()
+{
+ # usage: clip [ file/text ] <value>
+ : "${1:?}"
+ : "${2:?}"
+
+ if [ -n "$WAYLAND_DISPLAY" ]; then
+ dep_check "wl-copy"
+
+ [ "$1" = "text" ] &&
+ printf "%s" "$2" | wl-copy
+ [ "$1" = "file" ] &&
+ printf "file://%s" "$2" | wl-copy -t text/uri-list
+ elif [ -n "$DISPLAY" ]; then
+ dep_check "xclip"
+
+ [ "$1" = "text" ] &&
+ printf "%s" "$2" | xclip -selection clipboard
+ [ "$1" = "file" ] &&
+ printf "file://%s" "$2" | xclip -selection clipboard "$1" -t text/uri-list
+ fi
+
+ note "${1} coppied to clipboard"
+}
+
+set_menu()
+{
+ if [ -n "$WAYLAND_DISPLAY" ]; then
+ menu="$w_menu"
+ elif [ -n "$DISPLAY" ]; then
+ menu="$x_menu"
+ else
+ die "tty not supported"
+ fi
+}
+
+ip_menu()
+{
+ printf "" | "$menu" -p "${ico_dbk} ${1:?} "
+}
+
+key_menu()
+{
+ parse_data | "$menu" -l 25 -p "${ico_dbk} key " || return 1
+}
+
+
+########
+# MAIN #
+########
+
+key=
+value=
+
+[ -d "$book_data" ] ||
+ mkdir -p "$book_data"
+[ -d "$book_conf" ] ||
+ mkdir -p "${book_conf%/*}"
+
+set_menu
+case "$1" in
+-*) ;;
+"") ;;
+*) command="$1" && shift
+esac
+
+case "$command" in
+insert|save)
+ value="${1:-$(ip_menu "value")}" || exit 1
+ key="${2:-$(ip_menu "key")}" || exit 1
+ value="$(trim "$value")"
+ key="$(trim "$key")"
+
+ parse_data getval "$key" > /dev/null &&
+ die "key already in use"
+
+ case "$command" in
+ insert)
+ [ -e "$value" ] &&
+ value="$(realpath "$value")"
+ ;;
+ save)
+ [ -d "$value" ] &&
+ warn "${value} is a directory, will not be saved"
+ if [ -f "$value" ]; then
+ cp "$value" "$book_data"
+ value="${book_data}/$(basename "$value")"
+ fi
+ ;;
+ esac
+
+ case "$key" in
+ [![:cntrl:][:print:]]*) ;; # check for unicode chars
+ *) icon="$(load_icon "$value")"
+ esac
+
+ printf "%s\t|\t%s\n" "${icon:+$icon }$key" "$value" >> "$book_conf"
+ ;;
+rm)
+ key="${1:-$(key_menu)}" || exit 1
+
+ val="$(parse_data getval "$key")"
+ case "$val" in
+ ${book_data}/*) rm "$val";;
+ esac
+
+ rm_data "$key"
+ ;;
+"")
+ dep_check "xdg-open"
+ [ -s "$book_conf" ] ||
+ die "no bookmarks, try dbook -h"
+
+ key="${2:-$(key_menu)}" || exit 1
+ value="$(parse_data getval "$key")" ||
+ die "${key}: no such key"
+
+ case "$1" in
+ -t)
+ if [ -z "$WAYLAND_DISPLAY" ]
+ then
+ dep_check "xdotool"
+ xdotool type --delay 20 "$value"
+ else
+ dep_check "wtype"
+ wtype -d 20 "$value"
+ fi
+ ;;
+ -c)
+ case "$(file --brief --dereference --mime-type "$value")" in
+ text/*) clip text "$(cat "$value")" ;;
+ *'No such file or directory)') clip text "$value" ;;
+ *) clip file "$value"
+ esac
+ ;;
+ "")
+ xdg-open "$value" 2> /dev/null || clip text "$value" ;;
+ *)
+ die "${1}: invalid option"
+ esac
+ ;;
+help) usage ;;
+*) die "$command, invalid command"
+esac
diff --git a/home/wayland/pkgs/wayland-scripts/src/bin/freezshot b/home/wayland/pkgs/wayland-scripts/src/bin/freezshot
index 754064a..18f7b21 100755
--- a/home/wayland/pkgs/wayland-scripts/src/bin/freezshot
+++ b/home/wayland/pkgs/wayland-scripts/src/bin/freezshot
@@ -4,7 +4,7 @@ out_dir="${GRIM_DEFAULT_DIR:-${XDG_PICTURES_DIR:-.}}"
info() {
notify-send " freezhot" "$1"
- printf "\033[32;1merr: %b\032[0m\n" "$1"
+ printf "\033[32;1m%b\033[0m\n" "$1"
}
focused_clinet_name() {
diff --git a/home/wayland/pkgs/wayland-scripts/src/bin/pirowatch b/home/wayland/pkgs/wayland-scripts/src/bin/pirowatch
new file mode 100755
index 0000000..97f703e
--- /dev/null
+++ b/home/wayland/pkgs/wayland-scripts/src/bin/pirowatch
@@ -0,0 +1,107 @@
+#!/bin/sh
+
+# dir where files are cached
+cache_dir="${XDG_CACHE_HOME:-${HOME}/.cache}/pirowatch"
+# dir where torrent files are stored
+torrent_dir="${XDG_DOWNLOAD_DIR:-$HOME/Downloads}"
+torrent_port=49110
+dht_port=49130
+menu="bemenu"
+
+note()
+{
+ # usage: note "message"
+ : "${1:?}"
+
+ command -v "notify-send" 1>/dev/null &&
+ notify-send "󰎁 pirowatch" "$1"
+}
+
+die()
+{
+ # usage: die "reason" [exit_status]
+ : "${1:?}"
+
+ note "$1"
+
+ printf "\033[31;1merr: %b\033[0m\n" "$1"
+ exit "${2:-1}"
+}
+
+dep_check()
+{
+ # usage: dep_check "dep_1" ...
+ : "${1:?}"
+
+ for dep; do
+ command -v "$dep" 1>/dev/null ||
+ die "$dep not found, please install it" 127
+ done
+
+ unset dep
+}
+
+stream() {
+ # usage: stream "torrent"
+ : "${1:?}"
+
+ dep_check "webtorrent" "mpv"
+
+ command -v "notify-send" 1>/dev/null &&
+ note "connecting to peers, wait for few seconds"
+
+ if [ -n "$2" ]
+ then
+ webtorrent --mpv -o "$cache_dir" --torrent-port "$torrent_port" --dht-port "$dht_port" "$1" --select "$2"
+ else
+ webtorrent --mpv -o "$cache_dir" --torrent-port "$torrent_port" --dht-port "$dht_port" "$1"
+ fi ||
+ die "webtorrent failed to play"
+}
+
+set_index() {
+ # usage: get_index "torrent"
+ : "${1:?}"
+
+ dep_check "webtorrent" "$menu"
+
+ fetch=$(webtorrent -o "$cache_dir" --torrent-port "$torrent_port" --dht-port "$dht_port" "$1" --select |
+ grep -Ei "\.(mkv|mp4|webm|avi|mov|flv|flac|opus|ogg|mp3|wav) (.*)$")
+ if [ "$(echo "$fetch" | wc -l)" -gt 1 ]
+ then
+ fetch="$(printf "%s" "$fetch" | "$menu" -p "󰎁 " -l 25)" ||
+ die "empty selection" 66
+ fi
+
+ index="${fetch%%[[:space:]]*}"
+
+ unset fetch
+}
+
+main()
+{
+ torrent=
+ index="tobeset"
+
+ if [ "$1" = "-s" ]
+ then
+ index=
+ shift
+ fi
+ [ -z "$WAYLAND_DISPLAY" ] &&
+ menu="dmenu"
+
+ dep_check "$menu"
+
+ torrent="${1:-$torrent_dir/$(find "$torrent_dir" -type f -name "*.torrent" | sed 's/.*\///g' | "$menu" -p " " -l 25)}"
+ [ -z "${torrent##"${torrent_dir}"/}" ] &&
+ die "magnet or torrent file not entered" 66
+ [ -d "$cache_dir" ] ||
+ mkdir -p "$cache_dir"
+ [ "$index" = "tobeset" ] &&
+ set_index "$torrent"
+
+ stream "$torrent" "$index"
+}
+
+main "$@"
diff --git a/home/wayland/pkgs/wayland-scripts/src/bin/tcsv b/home/wayland/pkgs/wayland-scripts/src/bin/tcsv
new file mode 100755
index 0000000..3f16e52
--- /dev/null
+++ b/home/wayland/pkgs/wayland-scripts/src/bin/tcsv
@@ -0,0 +1,160 @@
+#!/bin/sh
+
+url_csv="https://torrents-csv.com"
+menu="bemenu"
+
+die()
+{
+ : "${1:?}"
+
+ command -v notify-send > /dev/null &&
+ notify-send "󰎁 torrents-csv" "$1"
+
+ printf "\033[31;1merr: %b\033[0m\n" "$1" 1>&2
+ exit "${2:-1}"
+}
+
+dep_check()
+{
+ : "${1:?}"
+
+ for dep; do
+ command -v "$dep" 1>/dev/null ||
+ die "${dep} not found, please install it" 127
+ done
+
+ unset dep
+}
+
+search_tcsv()
+{
+ : "${1:?}"
+ dep_check curl
+
+ curl "${url_csv}/service/search?q=$(echo "$1" | tr ' ' '+')" \
+ --silent \
+ --compressed \
+ --write-out "%{http_code}"
+}
+
+byttounit()
+{
+ # usage: bytounuit bytes
+ : "${1:?}"
+
+ if [ "$1" -lt 1024 ]; then
+ printf "%d B" "$1"
+ elif [ "$1" -lt 1048576 ]; then
+ printf "%.1f KB" "$(echo "$1 / 1024" | bc -l)"
+ elif [ "$1" -lt 1073741824 ]; then
+ printf "%.1f MB" "$(echo "$1 / 1048576" | bc -l)"
+ elif [ "$1" -lt 1099511627776 ]; then
+ printf "%.1f GB" "$(echo "$1 / 1073741824" | bc -l)"
+ else
+ printf "BIG B"
+ fi
+}
+
+parse_table()
+{
+ # usage: echo "$fetch" | parse_table
+ name=
+ sneed=
+ leech=
+ size=
+
+ while read -r line; do
+ case "$line" in
+ \"name\":\"*)
+ name="${line#*:\"}"
+ name="${name%\"}"
+ ;;
+ \"size_bytes\":*)
+ size="$(byttounit "${line#*:}")"
+ ;;
+ \"seeders\":*)
+ sneed="${line#*:}"
+ ;;
+ \"leechers\":*)
+ leech="${line#*:}"
+ ;;
+ \"scraped_date\":*)
+ printf "%4d  %4d  %8s %s\n" \
+ "$sneed" "$leech" "$size" "$name"
+ ;;
+ esac
+ done | "$menu" -p "󰎁 " -il 25 | sed 's/.* //g'
+
+ unset name sneed leech size
+}
+
+wheremag()
+{
+ # usage: echo "$fetch" | wheremag name
+ : "${1:?}"
+
+ name=
+ magnet=
+
+ while read -r line; do
+ case "$line" in
+ \"infohash\":\"*)
+ magnet="${line#*:\"}"
+ magnet="${magnet%\"}"
+ ;;
+ \"name\":\"*)
+ name="${line#*:\"}"
+ name="${name%\"}"
+
+ if [ "$name" = "$1" ]; then
+ echo "$magnet"
+ return
+ fi
+ ;;
+ esac
+ done
+
+ unset name magnet
+}
+
+query=
+fetch=
+data=
+name=
+magnet=
+
+[ -z "$WAYLAND_DISPLAY" ] &&
+ menu="dmenu"
+if [ "$#" -gt 0 ] && [ "$1" = "-o" ]; then
+ out=true
+ shift
+fi
+dep_check "$menu"
+
+query="${*:-$(printf "" | "$menu" -p "󱇒 ")}"
+[ -z "$query" ] &&
+ exit 1
+
+fetch="$(search_tcsv "$query")"
+case "$fetch" in
+*200)
+ [ "$fetch" = '[]200' ] &&
+ die "no results found"
+ data="$(echo "$fetch" | grep -o '"[^,}]*')"
+ ;;
+*)
+ die "search failed, check your internet connection"
+ ;;
+esac
+
+name="$(echo "$data" | parse_table)"
+[ -z "$name" ] &&
+ exit 1
+magnet="$(echo "$data" | wheremag "$name")"
+
+if [ "$out" = true ]; then
+ echo "$magnet"
+else
+ dep_check "pirowatch"
+ pirowatch "$magnet"
+fi
diff --git a/home/wayland/pkgs/wayland-scripts/src/bin/vpn b/home/wayland/pkgs/wayland-scripts/src/bin/vpn
new file mode 100755
index 0000000..db0353a
--- /dev/null
+++ b/home/wayland/pkgs/wayland-scripts/src/bin/vpn
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+exit_node="${1:-kay}"
+
+note()
+{
+ command -v notify-send > /dev/null &&
+ notify-send "󰒒 vpn" "$1"
+ printf "%s\n" "$1"
+}
+
+if tailscale exit-node list | grep -q "selected"; then
+ tailscale set --exit-node= &&
+ note "Connection was dropped"
+
+else
+ tailscale set --exit-node="$exit_node" &&
+ note "Traffic routed through $exit_node"
+fi