diff --git a/.gitignore b/.gitignore
index e7d64c1..31df7bd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,40 @@
!bin/statusbar
!bin/statusbar/*
+!bin/cron
+!bin/cron/*
+!bin/dmenu*
+!bin/getkeys
+!bin/ifinstalled
+!bin/lfub
+!bin/linkhandler
+!bin/maimpick
+!bin/noisereduce
+!bin/normalizer
+!bin/opout
+!bin/otp
+!bin/pauseallmpv
+!bin/peertubetorrent
+!bin/podentr
+!bin/prompt
+!bin/pygmentize
+!bin/qndl
+!bin/queueandnotify
+!bin/remaps
+!bin/rotdir
+!bin/rssadd
+!bin/samedir
+!bin/setbg
+!bin/shortcuts
+!bin/slider
+!bin/sysact
+!bin/tag
+!bin/td-toggle
+!bin/texclear
+!bin/torwrap
+!bin/transadd
+!bin/tutorialvids
+!bin/vpn
!share
!share/larbs
diff --git a/bin/getkeys b/bin/getkeys
new file mode 100755
index 0000000..266f29a
--- /dev/null
+++ b/bin/getkeys
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+cat "${XDG_DATA_HOME:-$HOME/.local/share}"/larbs/getkeys/"$1" 2>/dev/null && exit
+echo "Run command with one of the following arguments for info about that program:"
+ls "${XDG_DATA_HOME:-$HOME/.local/share}"/larbs/getkeys
diff --git a/bin/ifinstalled b/bin/ifinstalled
new file mode 100755
index 0000000..c192eba
--- /dev/null
+++ b/bin/ifinstalled
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# Some optional functions in LARBS require programs not installed by default. I
+# use this little script to check to see if a command exists and if it doesn't
+# it informs the user that they need that command to continue. This is used in
+# various other scripts for clarity's sake.
+
+for x in "$@"; do
+ if ! which "$x" >/dev/null 2>&1 && ! pacman -Qq "$x" >/dev/null 2>&1; then
+ notify-send "📦 $x" "must be installed for this function." && exit 1 ;
+ fi
+done
diff --git a/bin/lfub b/bin/lfub
new file mode 100755
index 0000000..9012f50
--- /dev/null
+++ b/bin/lfub
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+# This is a wrapper script for lb that allows it to create image previews with
+# ueberzug. This works in concert with the lf configuration file and the
+# lf-cleaner script.
+
+set -e
+
+cleanup() {
+ exec 3>&-
+ rm "$FIFO_UEBERZUG"
+}
+
+if [ -n "$SSH_CLIENT" ] || [ -n "$SSH_TTY" ]; then
+ lf "$@"
+else
+ [ ! -d "$HOME/.cache/lf" ] && mkdir -p "$HOME/.cache/lf"
+ export FIFO_UEBERZUG="$HOME/.cache/lf/ueberzug-$$"
+ mkfifo "$FIFO_UEBERZUG"
+ ueberzug layer -s <"$FIFO_UEBERZUG" -p json &
+ exec 3>"$FIFO_UEBERZUG"
+ trap cleanup HUP INT QUIT TERM PWR EXIT
+ lf "$@" 3>&-
+fi
diff --git a/bin/linkhandler b/bin/linkhandler
new file mode 100755
index 0000000..fa74caf
--- /dev/null
+++ b/bin/linkhandler
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+# Feed script a url or file location.
+# If an image, it will view in sxiv,
+# if a video or gif, it will view in mpv
+# if a music file or pdf, it will download,
+# otherwise it opens link in browser.
+
+# If no url given. Opens browser. For using script as $BROWSER.
+[ -z "$1" ] && { "$BROWSER"; exit; }
+
+case "$1" in
+ *mkv|*webm|*mp4|*youtube.com/watch*|*youtube.com/playlist*|*youtu.be*|*hooktube.com*|*bitchute.com*|*videos.lukesmith.xyz*|*odysee.com*)
+ setsid -f mpv -quiet "$1" >/dev/null 2>&1 ;;
+ *png|*jpg|*jpe|*jpeg|*gif)
+ curl -sL "$1" > "/tmp/$(echo "$1" | sed "s/.*\///;s/%20/ /g")" && sxiv -a "/tmp/$(echo "$1" | sed "s/.*\///;s/%20/ /g")" >/dev/null 2>&1 & ;;
+ *pdf|*cbz|*cbr)
+ curl -sL "$1" > "/tmp/$(echo "$1" | sed "s/.*\///;s/%20/ /g")" && zathura "/tmp/$(echo "$1" | sed "s/.*\///;s/%20/ /g")" >/dev/null 2>&1 & ;;
+ *mp3|*flac|*opus|*mp3?source*)
+ qndl "$1" 'curl -LO' >/dev/null 2>&1 ;;
+ *)
+ [ -f "$1" ] && setsid -f "$TERMINAL" -e "$EDITOR" "$1" >/dev/null 2>&1 || setsid -f "$BROWSER" "$1" >/dev/null 2>&1
+esac
diff --git a/bin/maimpick b/bin/maimpick
new file mode 100755
index 0000000..7125e61
--- /dev/null
+++ b/bin/maimpick
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+# This is bound to Shift+PrintScreen by default, requires maim. It lets you
+# choose the kind of screenshot to take, including copying the image or even
+# highlighting an area to copy. scrotcucks on suicidewatch right now.
+
+case "$(printf "a selected area\\ncurrent window\\nfull screen\\na selected area (copy)\\ncurrent window (copy)\\nfull screen (copy)" | dmenu -l 6 -i -p "Screenshot which area?")" in
+ "a selected area") maim -s pic-selected-"$(date '+%y%m%d-%H%M-%S').png" ;;
+ "current window") maim -i "$(xdotool getactivewindow)" pic-window-"$(date '+%y%m%d-%H%M-%S').png" ;;
+ "full screen") maim pic-full-"$(date '+%y%m%d-%H%M-%S').png" ;;
+ "a selected area (copy)") maim -s | xclip -selection clipboard -t image/png ;;
+ "current window (copy)") maim -i "$(xdotool getactivewindow)" | xclip -selection clipboard -t image/png ;;
+ "full screen (copy)") maim | xclip -selection clipboard -t image/png ;;
+esac
diff --git a/bin/noisereduce b/bin/noisereduce
new file mode 100755
index 0000000..c344760
--- /dev/null
+++ b/bin/noisereduce
@@ -0,0 +1,81 @@
+#!/usr/bin/sh
+
+usage ()
+{
+ printf "Usage : noisereduce \n"
+ exit
+}
+
+# Tests for requirements
+ifinstalled ffmpeg || { echo >&2 "We require 'ffmpeg' but it's not installed."; exit 1; }
+ifinstalled sox || { echo >&2 "We require 'ffmpeg' but it's not installed."; exit 1; }
+
+if [ "$#" -ne 2 ]
+then
+ usage
+fi
+
+if [ ! -e "$1" ]
+then
+ printf "File not found: %s\n" "$1"
+ exit
+fi
+
+if [ -e "$2" ]
+then
+ printf "File %s already exists, overwrite? [y/N]\n: " "$2"
+ read -r yn
+ case $yn in
+ [Yy]* ) ;;
+ * ) exit;;
+ esac
+fi
+
+inBasename=$(basename "$1")
+inExt="${inBasename##*.}"
+
+isVideoStr=$(ffprobe -v warning -show_streams "$1" | grep codec_type=video)
+if [ -n "$isVideoStr" ]
+then
+ isVideo=1
+ printf "Detected %s as a video file\n" "$inBasename"
+else
+ isVideo=0
+ printf "Detected %s as an audio file\n" "$inBasename"
+fi
+
+printf "Sample noise start time [00:00:00]: "
+read -r sampleStart
+if [ -z "$sampleStart" ] ; then sampleStart="00:00:00"; fi
+printf "Sample noise end time [00:00:00.900]: "
+read -r sampleEnd
+if [ -z "$sampleEnd" ] ; then sampleEnd="00:00:00.900"; fi
+printf "Noise reduction amount [0.21]: "
+read -r sensitivity
+if [ -z "$sensitivity" ] ; then sensitivity="0.21"; fi
+
+
+tmpVidFile="/tmp/noiseclean_tmpvid.$inExt"
+tmpAudFile="/tmp/noiseclean_tmpaud.wav"
+noiseAudFile="/tmp/noiseclean_noiseaud.wav"
+noiseProfFile="/tmp/noiseclean_noise.prof"
+tmpAudCleanFile="/tmp/noiseclean_tmpaud-clean.wav"
+
+printf "Cleaning noise on %s...\n" "$1"
+
+if [ $isVideo -eq "1" ]; then
+ ffmpeg -v warning -y -i "$1" -qscale:v 0 -vcodec copy -an "$tmpVidFile"
+ ffmpeg -v warning -y -i "$1" -qscale:a 0 "$tmpAudFile"
+else
+ cp "$1" "$tmpAudFile"
+fi
+ffmpeg -v warning -y -i "$1" -vn -ss "$sampleStart" -t "$sampleEnd" "$noiseAudFile"
+sox "$noiseAudFile" -n noiseprof "$noiseProfFile"
+sox "$tmpAudFile" "$tmpAudCleanFile" noisered "$noiseProfFile" "$sensitivity"
+if [ $isVideo -eq "1" ]; then
+ ffmpeg -v warning -y -i "$tmpAudCleanFile" -i "$tmpVidFile" -vcodec copy -qscale:v 0 -qscale:a 0 "$2"
+else
+ cp "$tmpAudCleanFile" "$2"
+fi
+
+printf "Done"
diff --git a/bin/normalizer b/bin/normalizer
new file mode 100755
index 0000000..2479e13
--- /dev/null
+++ b/bin/normalizer
@@ -0,0 +1,8 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+import re
+import sys
+from charset_normalizer.cli.normalizer import cli_detect
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+ sys.exit(cli_detect())
diff --git a/bin/opout b/bin/opout
new file mode 100755
index 0000000..faf6575
--- /dev/null
+++ b/bin/opout
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+# opout: "open output": A general handler for opening a file's intended output,
+# usually the pdf of a compiled document. I find this useful especially
+# running from vim.
+
+basename="${1%.*}"
+
+case "${*}" in
+ *.tex|*.m[dse]|*.[rR]md|*.mom|*.[0-9]) setsid -f xdg-open "$basename".pdf >/dev/null 2>&1 ;;
+ *.html) setsid -f "$BROWSER" "$basename".html >/dev/null 2>&1 ;;
+ *.sent) setsid -f sent "$1" >/dev/null 2>&1 ;;
+esac
diff --git a/bin/otp b/bin/otp
new file mode 100755
index 0000000..1726b1a
--- /dev/null
+++ b/bin/otp
@@ -0,0 +1,53 @@
+#!/bin/sh
+
+# Get a one-time password, or add a OTP secret to your pass-otp store.
+
+# The assumption of this script is that all otp passwords are stored with the
+# suffix `-otp`. This script automatically appends newly added otps as such.
+
+# For OTP passwords to be generated properly, it is important for the local
+# computer to have its time properly synced. This can be done with the command
+# below which requires the package `ntp`.
+
+ifinstalled pass pass-otp
+
+dir="${PASSWORD_STORE_DIR}"
+
+choice="$({ echo "🆕add" ; echo "🕙sync-time" ; ls ${dir}/*-otp.gpg ;} | sed "s/.*\///;s/-otp.gpg//" | dmenu -p "Pick a 2FA:")"
+
+case $choice in
+ 🆕add )
+ ifinstalled maim zbar xclip || exit 1
+
+ temp="$dir/temp.png"
+ otp="otp-test-script"
+ trap 'shred -fu $temp; pass rm $otp' HUP INT QUIT TERM PWR EXIT
+
+ notify-send "Scan the image." "Scan the OTP QR code."
+
+ maim -s "$temp" || exit 1
+ info="$(zbarimg -q "$temp")"
+ info="${info#QR-Code:}"
+ issuer="$(echo "$info" | grep -o "issuer=[A-z0-9]\+")"
+ name="${issuer#issuer=}"
+
+ if echo "$info" | pass otp insert "$otp"; then
+ while true ; do
+ export name="$(dmenu -p "Give this One Time Password a one-word name:")"
+ echo "$name" | grep -q -- "^[A-z0-9-]\+$" && break
+ done
+ pass mv "$otp" "$name-otp"
+ notify-send "Successfully added." "$name-otp has been created."
+ else
+ notify-send "No OTP data found." "Try to scan the image again more precisely."
+ fi
+
+ ;;
+ 🕙sync-time )
+ ifinstalled ntp || exit 1
+ notify-send -u low "🕙 Synchronizing Time..." "Synching time with remote NTP servers..."
+ updatedata="$(sudo ntpdate pool.ntp.org)" &&
+ notify-send -u low "🕙 Synchronizing Time..." "Done. Time changed by ${updatedata#*offset }"
+ ;;
+ *) pass otp -c ${choice}-otp ;;
+esac
diff --git a/bin/pauseallmpv b/bin/pauseallmpv
new file mode 100755
index 0000000..d69a414
--- /dev/null
+++ b/bin/pauseallmpv
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# You might notice all mpv commands are aliased to have this input-ipc-server
+# thing. That's just for this particular command, which allows us to pause
+# every single one of them with one command! This is bound to super + shift + p
+# (with other things) by default and is used in some other places.
+
+for i in $(ls /tmp/mpvSockets/*); do
+ echo '{ "command": ["set_property", "pause", true] }' | socat - "$i";
+done
diff --git a/bin/peertubetorrent b/bin/peertubetorrent
new file mode 100755
index 0000000..7a7a483
--- /dev/null
+++ b/bin/peertubetorrent
@@ -0,0 +1,7 @@
+#!/bin/sh
+# torrent peertube videos, requires the transadd script
+# first argument is the video link, second is the quality (480 or 1080)
+# 13/07/20 - Arthur Bais
+
+link="$(echo "$1" | sed "s/w/download\/torrents/")""-$2.torrent"
+transadd "$link"
diff --git a/bin/podentr b/bin/podentr
new file mode 100755
index 0000000..9454b07
--- /dev/null
+++ b/bin/podentr
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# entr command to run `queueandnotify` when newsboat queue is changed
+
+[ "$(pgrep -x "$(basename "$0")" | wc -l)" -gt 2 ] && exit
+
+echo "${XDG_DATA_HOME:-$HOME/.local/share}"/newsboat/queue | entr -p queueandnotify 2>/dev/null
diff --git a/bin/prompt b/bin/prompt
new file mode 100755
index 0000000..666434f
--- /dev/null
+++ b/bin/prompt
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+# A dmenu binary prompt script.
+# Gives a dmenu prompt labeled with $1 to perform command $2.
+# For example:
+# `./prompt "Do you want to shutdown?" "shutdown -h now"`
+
+[ "$(printf "No\\nYes" | dmenu -i -p "$1" -nb darkred -sb red -sf white -nf gray )" = "Yes" ] && $2
diff --git a/bin/pygmentize b/bin/pygmentize
new file mode 100755
index 0000000..3b60d99
--- /dev/null
+++ b/bin/pygmentize
@@ -0,0 +1,8 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+import re
+import sys
+from pygments.cmdline import main
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+ sys.exit(main())
diff --git a/bin/qndl b/bin/qndl
new file mode 100755
index 0000000..48bc61e
--- /dev/null
+++ b/bin/qndl
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# $1 is a url; $2 is a command
+[ -z "$1" ] && exit
+base="$(basename "$1")"
+notify-send "⏳ Queuing $base..."
+cmd="$2"
+[ -z "$cmd" ] && cmd="yt-dlp --embed-metadata -ic"
+idnum="$(tsp $cmd "$1")"
+realname="$(echo "$base" | sed "s/?\(source\|dest\).*//;s/%20/ /g")"
+tsp -D "$idnum" mv "$base" "$realname"
+tsp -D "$idnum" notify-send "👍 $realname done."
diff --git a/bin/queueandnotify b/bin/queueandnotify
new file mode 100755
index 0000000..1c3025c
--- /dev/null
+++ b/bin/queueandnotify
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+# Podboat sucks. This script replaces it.
+# It reads the newsboat queue, queuing downloads with taskspooler.
+# It also removes the junk from extensions.
+queuefile="${XDG_DATA_HOME:-$HOME/.local/share}/newsboat/queue"
+
+while read -r line; do
+ [ -z "$line" ] && continue
+ url="${line%%[ ]*}"
+ qndl "$url" "curl -LO"
+done < "$queuefile"
+
+echo > "$queuefile"
diff --git a/bin/remaps b/bin/remaps
new file mode 100755
index 0000000..3cb41e4
--- /dev/null
+++ b/bin/remaps
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+# This script is called on startup to remap keys.
+# Increase key speed via a rate change
+xset r rate 300 50
+# Map the caps lock key to super...
+setxkbmap -option caps:super
+# But when it is pressed only once, treat it as escape.
+killall xcape 2>/dev/null ; xcape -e 'Super_L=Escape'
+# Map the menu button to right super as well.
+xmodmap -e 'keycode 135 = Super_R'
+# Turn off the caps lock if on since there is no longer a key for it.
+xset -q | grep "Caps Lock:\s*on" && xdotool key Caps_Lock
diff --git a/bin/rotdir b/bin/rotdir
new file mode 100755
index 0000000..86da6db
--- /dev/null
+++ b/bin/rotdir
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# When I open an image from the file manager in sxiv (the image viewer), I want
+# to be able to press the next/previous keys to key through the rest of the
+# images in the same directory. This script "rotates" the content of a
+# directory based on the first chosen file, so that if I open the 15th image,
+# if I press next, it will go to the 16th etc. Autistic, I know, but this is
+# one of the reasons that sxiv is great for being able to read standard input.
+
+[ -z "$1" ] && echo "usage: rotdir regex 2>&1" && exit 1
+base="$(basename "$1")"
+ls "$PWD" | awk -v BASE="$base" 'BEGIN { lines = ""; m = 0; } { if ($0 == BASE) { m = 1; } } { if (!m) { if (lines) { lines = lines"\n"; } lines = lines""$0; } else { print $0; } } END { print lines; }'
diff --git a/bin/rssadd b/bin/rssadd
new file mode 100755
index 0000000..910fca3
--- /dev/null
+++ b/bin/rssadd
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+if echo "$1" | grep -q "https*://\S\+\.[A-Za-z]\+\S*" ; then
+ url="$1"
+else
+ url="$(grep -Eom1 '<[^>]+(rel="self"|application/[a-z]+\+xml)[^>]+>' "$1" |
+ grep -o "https?://[^\" ]")"
+
+ echo "$url" | grep -q "https*://\S\+\.[A-Za-z]\+\S*" ||
+ notify-send "That doesn't look like a full URL." && exit 1
+fi
+
+RSSFILE="${XDG_CONFIG_HOME:-$HOME/.config}/newsboat/urls"
+if awk '{print $1}' "$RSSFILE" | grep "^$url$" >/dev/null; then
+ notify-send "You already have this RSS feed."
+else
+ echo "$url" >> "$RSSFILE" && notify-send "RSS feed added."
+fi
diff --git a/bin/samedir b/bin/samedir
new file mode 100755
index 0000000..0a19707
--- /dev/null
+++ b/bin/samedir
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# Open a terminal window in the same directory as the currently active window.
+
+PID=$(xprop -id "$(xprop -root | xprop -root | sed -n "/_NET_ACTIVE_WINDOW/ s/^.*# // p")" | sed -n "/PID/ s/^.*= // p")
+PID="$(pstree -lpA "$PID")"
+PID="${PID##*(}"
+PID="${PID%)}"
+cd "$(readlink /proc/"$PID"/cwd)" || return 1
+"$TERMINAL"
diff --git a/bin/setbg b/bin/setbg
new file mode 100755
index 0000000..2829896
--- /dev/null
+++ b/bin/setbg
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+# This script does the following:
+# Run by itself, set the wallpaper (at X start).
+# If given a file, set that as the new wallpaper.
+# If given a directory, choose random file in it.
+# If wal is installed, also generates a colorscheme.
+
+# Location of link to wallpaper link.
+bgloc="${XDG_DATA_HOME:-$HOME/.local/share}/bg"
+
+# Configuration files of applications that have their themes changed by pywal.
+dunstconf="${XDG_CONFIG_HOME:-$HOME/.config}/dunst/dunstrc"
+zathuraconf="${XDG_CONFIG_HOME:-$HOME/.config}/zathura/zathurarc"
+
+trueloc="$(readlink -f "$1")" &&
+case "$(file --mime-type -b "$trueloc")" in
+ image/* ) ln -sf "$(readlink -f "$1")" "$bgloc" && notify-send -i "$bgloc" "Changing wallpaper..." ;;
+ inode/directory ) ln -sf "$(find "$trueloc" -iregex '.*.\(jpg\|jpeg\|png\|gif\)' -type f | shuf -n 1)" "$bgloc" && notify-send -i "$bgloc" "Random Wallpaper chosen." ;;
+ *) notify-send "Error" "Not a valid image." ; exit 1;;
+esac
+
+# If pywal is installed, use it.
+if command -v wal >/dev/null 2>&1 ; then
+ wal -i "$(readlink -f $bgloc)" -o "${XDG_CONFIG_HOME:-$HOME/.config}/wal/postrun" >/dev/null 2>&1 &&
+ pidof dwm >/dev/null && xdotool key super+F12
+# If pywal is removed, return config files to normal.
+else
+ [ -f "$dunstconf.bak" ] && unlink "$dunstconf" && mv "$dunstconf.bak" "$dunstconf"
+ [ -f "$zathuraconf.bak" ] && unlink "$zathuraconf" && mv "$zathuraconf.bak" "$zathuraconf"
+fi
+
+xwallpaper --zoom "$bgloc"
diff --git a/bin/shortcuts b/bin/shortcuts
new file mode 100755
index 0000000..8fecea2
--- /dev/null
+++ b/bin/shortcuts
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+bmdirs="${XDG_CONFIG_HOME:-$HOME/.config}/shell/bm-dirs"
+bmfiles="${XDG_CONFIG_HOME:-$HOME/.config}/shell/bm-files"
+
+# Output locations. Unactivated progs should go to /dev/null.
+shell_shortcuts="${XDG_CONFIG_HOME:-$HOME/.config}/shell/shortcutrc"
+zsh_named_dirs="${XDG_CONFIG_HOME:-$HOME/.config}/shell/zshnameddirrc"
+lf_shortcuts="${XDG_CONFIG_HOME:-$HOME/.config}/lf/shortcutrc"
+vim_shortcuts="${XDG_CONFIG_HOME:-$HOME/.config}/nvim/shortcuts.vim"
+ranger_shortcuts="/dev/null"
+qute_shortcuts="/dev/null"
+fish_shortcuts="/dev/null"
+vifm_shortcuts="/dev/null"
+
+# Remove, prepare files
+rm -f "$lf_shortcuts" "$ranger_shortcuts" "$qute_shortcuts" "$zsh_named_dirs" "$vim_shortcuts" 2>/dev/null
+printf "# vim: filetype=sh\\n" > "$fish_shortcuts"
+printf "# vim: filetype=sh\\nalias " > "$shell_shortcuts"
+printf "\" vim: filetype=vim\\n" > "$vifm_shortcuts"
+
+# Format the `directories` file in the correct syntax and sent it to all three configs.
+eval "echo \"$(cat "$bmdirs")\"" | \
+awk "!/^\s*#/ && !/^\s*\$/ {gsub(\"\\\s*#.*$\",\"\");
+ printf(\"%s=\42cd %s && ls -a\42 \\\\\n\",\$1,\$2) >> \"$shell_shortcuts\" ;
+ printf(\"hash -d %s=%s \n\",\$1,\$2) >> \"$zsh_named_dirs\" ;
+ printf(\"abbr %s \42cd %s; and ls -a\42\n\",\$1,\$2) >> \"$fish_shortcuts\" ;
+ printf(\"map g%s :cd %s\nmap t%s :cd %s\nmap M%s :cd %s:mo\nmap Y%s :cd %s:co \n\",\$1,\$2, \$1, \$2, \$1, \$2, \$1, \$2) >> \"$vifm_shortcuts\" ;
+ printf(\"config.bind(';%s', \42set downloads.location.directory %s ;; hint links download\42) \n\",\$1,\$2) >> \"$qute_shortcuts\" ;
+ printf(\"map g%s cd %s\nmap t%s tab_new %s\nmap m%s shell mv -v %%s %s\nmap Y%s shell cp -rv %%s %s \n\",\$1,\$2,\$1,\$2, \$1, \$2, \$1, \$2) >> \"$ranger_shortcuts\" ;
+ printf(\"map C%s cd \42%s\42 \n\",\$1,\$2) >> \"$lf_shortcuts\" ;
+ printf(\"cmap ;%s %s\n\",\$1,\$2) >> \"$vim_shortcuts\" }"
+
+# Format the `files` file in the correct syntax and sent it to both configs.
+eval "echo \"$(cat "$bmfiles")\"" | \
+awk "!/^\s*#/ && !/^\s*\$/ {gsub(\"\\\s*#.*$\",\"\");
+ printf(\"%s=\42\$EDITOR %s\42 \\\\\n\",\$1,\$2) >> \"$shell_shortcuts\" ;
+ printf(\"hash -d %s=%s \n\",\$1,\$2) >> \"$zsh_named_dirs\" ;
+ printf(\"abbr %s \42\$EDITOR %s\42 \n\",\$1,\$2) >> \"$fish_shortcuts\" ;
+ printf(\"map %s :e %s \n\",\$1,\$2) >> \"$vifm_shortcuts\" ;
+ printf(\"map %s shell \$EDITOR %s \n\",\$1,\$2) >> \"$ranger_shortcuts\" ;
+ printf(\"map E%s \$\$EDITOR \42%s\42 \n\",\$1,\$2) >> \"$lf_shortcuts\" ;
+ printf(\"cmap ;%s %s\n\",\$1,\$2) >> \"$vim_shortcuts\" }"
diff --git a/bin/slider b/bin/slider
new file mode 100755
index 0000000..674781a
--- /dev/null
+++ b/bin/slider
@@ -0,0 +1,126 @@
+#!/bin/sh
+
+# Give a file with images and timecodes and creates a video slideshow of them.
+#
+# Timecodes must be in format 00:00:00.
+#
+# Imagemagick and ffmpeg required.
+
+# Application cache if not stated elsewhere.
+cache="${XDG_CACHE_HOME:-$HOME/.cache}/slider"
+
+while getopts "hvrpi:c:a:o:d:f:t:e:x:" o; do case "${o}" in
+ c) bgc="$OPTARG" ;;
+ t) fgc="$OPTARG" ;;
+ f) font="$OPTARG" ;;
+ i) file="$OPTARG" ;;
+ a) audio="$OPTARG" ;;
+ o) outfile="$OPTARG" ;;
+ d) prepdir="$OPTARG" ;;
+ r) redo="$OPTARG" ;;
+ s) ppt="$OPTARG" ;;
+ e) endtime="$OPTARG" ;;
+ x) res="$OPTARG"
+ echo "$res" | grep -qv "^[0-9]\+x[0-9]\+$" &&
+ echo "Resolution must be dimensions separated by a 'x': 1280x720, etc." &&
+ exit 1 ;;
+ p) echo "Purge old build files in $cache? [y/N]"
+ read -r confirm
+ echo "$confirm" | grep -iq "^y$" && rm -rf "$cache" && echo "Done."
+ exit ;;
+ v) verbose=True ;;
+ *) echo "$(basename "$0") usage:
+ -i input timecode list (required)
+ -a audio file
+ -c color of background (use html names, black is default)
+ -t text color for text slides (white is default)
+ -s text font size for text slides (150 is default)
+ -f text font for text slides (sans serif is default)
+ -o output video file
+ -e if no audio given, the time in seconds that the last slide will be shown (5 is default)
+ -x resolution (1920x1080 is default)
+ -d tmp directory
+ -r rerun imagemagick commands even if done previously (in case files or background has changed)
+ -p purge old build files instead of running
+ -v be verbose" && exit 1
+
+esac done
+
+# Check that the input file looks like it should.
+{ head -n 1 "$file" 2>/dev/null | grep -q "^00:00:00 " ;} || {
+ echo "Give an input file with -i." &&
+ echo "The file should look as this example:
+
+00:00:00 first_image.jpg
+00:00:03 otherdirectory/next_image.jpg
+00:00:09 this_image_starts_at_9_seconds.jpg
+etc...
+
+Timecodes and filenames must be separated by Tabs." &&
+ exit 1
+ }
+
+if [ -n "${audio+x}" ]; then
+ # Check that the audio file looks like an actual audio file.
+ case "$(file --dereference --brief --mime-type -- "$audio")" in
+ audio/*) ;;
+ *) echo "That doesn't look like an audio file."; exit 1 ;;
+ esac
+ totseconds="$(date '+%s' -d $(ffmpeg -i "$audio" 2>&1 | awk '/Duration/ {print $2}' | sed s/,//))"
+ endtime="$((totseconds-seconds))"
+fi
+
+prepdir="${prepdir:-$cache/$file}"
+outfile="${outfile:-$file.mp4}"
+prepfile="$prepdir/$file.prep"
+
+[ -n "${verbose+x}" ] && echo "Preparing images... May take a while depending on the number of files."
+mkdir -p "$prepdir"
+
+{
+while read -r x;
+do
+ # Get the time from the first column.
+ time="${x%% *}"
+ seconds="$(date '+%s' -d "$time")"
+ # Duration is not used on the first looped item.
+ duration="$((seconds - prevseconds))"
+
+ # Get the filename/text content from the rest.
+ content="${x#* }"
+ base="$(basename "$content")"
+ base="${base%.*}.jpg"
+
+ if [ -f "$content" ]; then
+ # If images have already been made in a previous run, do not recreate
+ # them unless -r was given.
+ { [ ! -f "$prepdir/$base" ] || [ -n "${redo+x}" ] ;} &&
+ convert -size "${res:-1920x1080}" canvas:"${bgc:-black}" -gravity center "$content" -resize 1920x1080 -composite "$prepdir/$base"
+ else
+ { [ ! -f "$prepdir/$base" ] || [ -n "${redo+x}" ] ;} &&
+ convert -size "${res:-1920x1080}" -background "${bgc:-black}" -fill "${fgc:-white}" -font "${font:-Sans}" -pointsize "${ppt:-150}" -gravity center label:"$content" "$prepdir/$base"
+ fi
+
+ # If the first line, do not write yet.
+ [ "$time" = "00:00:00" ] || echo "file '$prevbase'
+duration $duration"
+
+ # Keep the information required for the next file.
+ prevbase="$base"
+ prevtime="$time"
+ prevseconds="$(date '+%s' -d "$prevtime")"
+done < "$file"
+# Do last file which must be given twice as follows
+echo "file '$base'
+duration ${endtime:-5}
+file '$base'"
+} > "$prepfile"
+if [ -n "${audio+x}" ]; then
+ ffmpeg -hide_banner -y -f concat -safe 0 -i "$prepfile" -i "$audio" -c:a aac -vsync vfr -c:v libx264 -pix_fmt yuv420p "$outfile"
+else
+ ffmpeg -hide_banner -y -f concat -safe 0 -i "$prepfile" -vsync vfr -c:v libx264 -pix_fmt yuv420p "$outfile"
+fi
+
+# Might also try:
+# -vf "fps=${fps:-24},format=yuv420p" "$outfile"
+# but has given some problems.
diff --git a/bin/sysact b/bin/sysact
new file mode 100755
index 0000000..948b44b
--- /dev/null
+++ b/bin/sysact
@@ -0,0 +1,28 @@
+#!/bin/sh
+# A dmenu wrapper script for system functions.
+case "$(readlink -f /sbin/init)" in
+ *systemd*) ctl='systemctl' ;;
+ *) ctl='loginctl' ;;
+esac
+
+lock=" lock"
+leave=" leave dwm"
+renew=" renew dwm"
+hibernate=" hibernate"
+reboot=" reboot"
+shutdown=" shutdown"
+sleep=" sleep"
+display=" display off"
+
+case "$(printf "$lock\n$leave\n$renew\n$hibernate\n$reboot\n$shutdown\n$sleep\n$display" \
+ | dmenu -i -p 'Action: ')" in
+ $lock) slock ;;
+ $leave) kill -TERM "$(pgrep -u "$USER" "\bdwm$")" ;;
+ $renew) kill -HUP "$(pgrep -u "$USER" "\bdwm$")" ;;
+ $hibernate) slock $ctl hibernate ;;
+ $sleep) slock $ctl suspend -i ;;
+ $reboot) $ctl reboot -i ;;
+ $shutdown) $ctl poweroff -i ;;
+ $display) xset dpms force off ;;
+ *) exit 1 ;;
+esac
diff --git a/bin/tag b/bin/tag
new file mode 100755
index 0000000..8462b99
--- /dev/null
+++ b/bin/tag
@@ -0,0 +1,67 @@
+#!/bin/sh
+
+err() { echo "Usage:
+ tag [OPTIONS] file
+Options:
+ -a: artist/author
+ -t: song/chapter title
+ -A: album/book title
+ -n: track/chapter number
+ -N: total number of tracks/chapters
+ -d: year of publication
+ -g: genre
+ -c: comment
+You will be prompted for title, artist, album and track if not given." && exit 1 ;}
+
+while getopts "a:t:A:n:N:d:g:c:f:" o; do case "${o}" in
+ a) artist="${OPTARG}" ;;
+ t) title="${OPTARG}" ;;
+ A) album="${OPTARG}" ;;
+ n) track="${OPTARG}" ;;
+ N) total="${OPTARG}" ;;
+ d) date="${OPTARG}" ;;
+ g) genre="${OPTARG}" ;;
+ c) comment="${OPTARG}" ;;
+ f) file="${OPTARG}" ;;
+ *) printf "Invalid option: -%s\\n" "$OPTARG" && err ;;
+esac done
+
+shift $((OPTIND - 1))
+
+file="$1"
+
+[ ! -f "$file" ] && echo "Provide file to tag." && err
+
+[ -z "$title" ] && echo "Enter a title." && read -r title
+[ -z "$artist" ] && echo "Enter an artist." && read -r artist
+[ -z "$album" ] && echo "Enter an album." && read -r album
+[ -z "$track" ] && echo "Enter a track number." && read -r track
+
+case "$file" in
+ *.ogg) echo "Title=$title
+Artist=$artist
+Album=$album
+Track=$track
+Total=$total
+Date=$date
+Genre=$genre
+Comment=$comment" | vorbiscomment -w "$file" ;;
+ *.opus) echo "Title=$title
+Artist=$artist
+Album=$album
+Track=$track
+Total=$total
+Date=$date
+Genre=$genre
+Comment=$comment" | opustags -i -S "$file" ;;
+ *.mp3) eyeD3 -Q --remove-all -a "$artist" -A "$album" -t "$title" -n "$track" -N "$total" -Y "$date" "$file" ;;
+ *.flac) echo "TITLE=$title
+ARTIST=$artist
+ALBUM=$album
+TRACKNUMBER=$track
+TOTALTRACKS=$total
+DATE=$date
+GENRE=$genre
+DESCRIPTION=$comment" | metaflac --remove-all-tags --import-tags-from=- "$file" ;;
+ *) echo "File type not implemented yet." ;;
+esac
diff --git a/bin/td-toggle b/bin/td-toggle
new file mode 100755
index 0000000..3c20ea1
--- /dev/null
+++ b/bin/td-toggle
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# If transmission-daemon is running, will ask to kill, else will ask to start.
+
+if pidof transmission-daemon >/dev/null ;
+then
+ [ "$(printf "No\\nYes" | dmenu -i -p "Turn off transmission-daemon?")" = "Yes" ] && killall transmission-da && notify-send "transmission-daemon disabled."
+else
+ ifinstalled transmission-cli || exit
+ [ "$(printf "No\\nYes" | dmenu -i -p "Turn on transmission daemon?")" = "Yes" ] && transmission-daemon && notify-send "transmission-daemon enabled."
+fi
+sleep 3 && pkill -RTMIN+7 "${STATUSBAR:-dwmblocks}"
diff --git a/bin/texclear b/bin/texclear
new file mode 100755
index 0000000..f38f7be
--- /dev/null
+++ b/bin/texclear
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+# Clears the build files of a LaTeX/XeLaTeX build.
+# I have vim run this file whenever I exit a .tex file.
+
+case "$1" in
+ *.tex)
+ file=$(readlink -f "$1")
+ dir=$(dirname "$file")
+ base="${file%.*}"
+ find "$dir" -maxdepth 1 -type f -regextype gnu-awk -regex "^$base\\.(4tc|xref|tmp|pyc|pyg|pyo|fls|vrb|fdb_latexmk|bak|swp|aux|log|synctex\\(busy\\)|lof|lot|maf|idx|mtc|mtc0|nav|out|snm|toc|bcf|run\\.xml|synctex\\.gz|blg|bbl)" -delete
+ rm -rdf "$dir/_minted-$(basename -- $base)"
+ ;;
+ *) printf "Give .tex file as argument.\\n" ;;
+esac
+
diff --git a/bin/torwrap b/bin/torwrap
new file mode 100755
index 0000000..8b20ad4
--- /dev/null
+++ b/bin/torwrap
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+ifinstalled tremc transmission-cli || exit
+
+! pidof transmission-daemon >/dev/null && transmission-daemon && notify-send "Starting torrent daemon..."
+
+$TERMINAL -e tremc; pkill -RTMIN+7 "${STATUSBAR:-dwmblocks}"
diff --git a/bin/transadd b/bin/transadd
new file mode 100755
index 0000000..a598fad
--- /dev/null
+++ b/bin/transadd
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+# Mimeapp script for adding torrent to transmission-daemon, but will also start the daemon first if not running.
+
+# transmission-daemon sometimes fails to take remote requests in its first moments, hence the sleep.
+
+pidof transmission-daemon >/dev/null || (transmission-daemon && notify-send "Starting transmission daemon..." && sleep 3 && pkill -RTMIN+7 "${STATUSBAR:-dwmblocks}")
+
+transmission-remote -a "$@" && notify-send "🔽 Torrent added."
diff --git a/bin/tutorialvids b/bin/tutorialvids
new file mode 100755
index 0000000..6d4914b
--- /dev/null
+++ b/bin/tutorialvids
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+# This gives the user a list of videos they can select and watch without a
+# browser. If you want to check a tutorial video, it makes it easy. I'll
+# add/remove videos from this list as I go on.
+
+vidlist="
+dwm (window manager) https://videos.lukesmith.xyz/videos/watch/f6b78db7-b368-4647-bc64-28c08fff1988
+pacman (installing/managing programs) https://videos.lukesmith.xyz/videos/watch/8e7cadb9-0fed-47ce-a2a8-6635fa48614b
+status bar https://videos.lukesmith.xyz/videos/watch/a4d5326b-0aac-496e-bfc3-5acd5cee89f0
+sxiv (image viewer) https://videos.lukesmith.xyz/videos/watch/ad4c8d85-90c3-4f3d-a1f3-89129e64a3c2
+st (terminal) https://videos.lukesmith.xyz/videos/watch/efddd39d-bac5-4599-b572-177beb4ce6e8
+i3 (old window manager) https://videos.lukesmith.xyz/videos/watch/b861525c-7ada-40ee-a2bb-b5e1ffe0f48b
+neomutt (email) https://videos.lukesmith.xyz/videos/watch/83122e83-52d9-4278-ae1a-7d1beeb50c8e
+ncmpcpp (music player) https://videos.lukesmith.xyz/videos/watch/b5ac6f0d-a220-4433-88e3-e98fc791dc0a
+newsboat (RSS reader) https://videos.lukesmith.xyz/videos/watch/bd2c3fff-40fa-47ea-aa98-5b1ec0c903b6
+lf (file manager) https://videos.lukesmith.xyz/w/rKeHsF5ZHDNDbR1buUKB1c
+zathura (pdf viewer) https://videos.lukesmith.xyz/videos/watch/c780f75a-11f6-48a9-a191-d079ebc36ea4
+gpg keys https://videos.lukesmith.xyz/videos/watch/040f5530-4830-4583-9ddc-2080b421531b
+calcurse (calendar) https://videos.lukesmith.xyz/videos/watch/4b937e8b-7654-46e3-8d01-79392ec5b3d1
+urlview https://videos.lukesmith.xyz/videos/watch/31a4918f-633b-4bd6-b08e-956ac75d0324
+colorschemes with pywal https://videos.lukesmith.xyz/videos/watch/1b476003-61b2-4609-ac4b-820c3d128643
+vi mode in shell https://videos.lukesmith.xyz/videos/watch/228aa50c-836f-456f-9f0d-a45157fe4313
+pass (password manager) https://videos.lukesmith.xyz/videos/watch/432fc942-5e28-4682-9beb-f5cb237a1dd6
+"
+echo "$vidlist" | grep -P "^$(echo "$vidlist" | grep "https:" | sed 's/\t.*//g' | dmenu -i -p "Learn about what? (ESC to cancel)" -l 20 | awk '{print $1}')\s" | sed 's/.*\t//' | xargs -r mpv
diff --git a/bin/vpn b/bin/vpn
new file mode 100755
index 0000000..ee0da07
--- /dev/null
+++ b/bin/vpn
@@ -0,0 +1,3 @@
+#!/bin/bash
+cloudflared access tcp --hostname openvpn.wessel.gg --url 127.0.0.1:9393 &
+sudo openvpn /mnt/Users/wesse/Documents/laptop-helix.ovpn &