summaryrefslogtreecommitdiff
path: root/.local
diff options
context:
space:
mode:
Diffstat (limited to '.local')
-rwxr-xr-x.local/bin/compiler53
-rw-r--r--.local/bin/cron/README.md11
-rw-r--r--.local/bin/cron/checkup17
-rw-r--r--.local/bin/cron/crontog6
-rw-r--r--.local/bin/cron/newsup15
-rwxr-xr-x.local/bin/displayselect82
-rwxr-xr-x.local/bin/dmenuhandler20
-rwxr-xr-x.local/bin/dmenupass6
-rwxr-xr-x.local/bin/dmenuunicode18
-rwxr-xr-x.local/bin/getkeys5
-rwxr-xr-x.local/bin/lfub25
-rwxr-xr-x.local/bin/linkhandler26
-rwxr-xr-x.local/bin/maimpick18
-rwxr-xr-x.local/bin/mounter114
-rwxr-xr-x.local/bin/noisereduce81
-rwxr-xr-x.local/bin/remaps14
-rwxr-xr-x.local/bin/sbackup11
-rwxr-xr-x.local/bin/slider126
-rwxr-xr-x.local/bin/statusbar/sb-battery37
-rw-r--r--.local/bin/statusbar/sb-bluetooth [TODO]0
-rwxr-xr-x.local/bin/statusbar/sb-clock33
-rwxr-xr-x.local/bin/statusbar/sb-cpu12
-rwxr-xr-x.local/bin/statusbar/sb-cpubars44
-rwxr-xr-x.local/bin/statusbar/sb-disk23
-rwxr-xr-x.local/bin/statusbar/sb-help-icon20
-rwxr-xr-x.local/bin/statusbar/sb-internet33
-rwxr-xr-x.local/bin/statusbar/sb-kbselect17
-rwxr-xr-x.local/bin/statusbar/sb-mailbox [TODO]20
-rwxr-xr-x.local/bin/statusbar/sb-memory13
-rwxr-xr-x.local/bin/statusbar/sb-mpdup8
-rwxr-xr-x.local/bin/statusbar/sb-music [TODO]19
-rwxr-xr-x.local/bin/statusbar/sb-news17
-rwxr-xr-x.local/bin/statusbar/sb-pacpackages29
-rwxr-xr-x.local/bin/statusbar/sb-popupgrade9
-rwxr-xr-x.local/bin/statusbar/sb-tasks [TODO]16
-rwxr-xr-x.local/bin/statusbar/sb-volume39
-rwxr-xr-x.local/bin/statusbar/sb-write20
-rwxr-xr-x.local/bin/transadd9
m---------.local/src/dmenu0
m---------.local/src/dwm0
m---------.local/src/dwmblocks0
m---------.local/src/st0
m---------.local/src/surf0
43 files changed, 1066 insertions, 0 deletions
diff --git a/.local/bin/compiler b/.local/bin/compiler
new file mode 100755
index 0000000..2c4fdf6
--- /dev/null
+++ b/.local/bin/compiler
@@ -0,0 +1,53 @@
+#!/bin/sh
+#
+# Compiles .tex. groff (.mom, .ms), .rmd, .md, .org. Opens .sent files as sent
+# presentations. Runs scripts based on extension or shebang.
+
+file=$(readlink -f "$1")
+dir=${file%/*}
+base="${file%.*}"
+ext="${file##*.}"
+
+cd "$dir" || exit 1
+
+textype() { \
+ textarget="$(getcomproot "$file" || echo "$file")"
+ echo "$textarget"
+ command="pdflatex"
+ ( head -n5 "$textarget" | grep -qi 'xelatex' ) && command="xelatex"
+ $command --output-directory="${textarget%/*}" "${textarget%.*}"
+ grep -qi addbibresource "$textarget" &&
+ biber --input-directory "${textarget%/*}" "${textarget%.*}" &&
+ $command --output-directory="${textarget%/*}" "${textarget%.*}" &&
+ $command --output-directory="${textarget%/*}" "${textarget%.*}"
+}
+
+case "$ext" in
+ # Try to keep these cases in alphabetical order.
+ [0-9]) preconv "$file" | refer -PS -e | groff -mandoc -T pdf > "$base".pdf ;;
+ c) cc "$file" -o "$base" && "$base" ;;
+ cpp) g++ "$file" -o "$base" && "$base" ;;
+ cs) mcs "$file" && mono "$base".exe ;;
+ go) go run "$file" ;;
+ h) sudo make install ;;
+ java) javac -d classes "$file" && java -cp classes "${1%.*}" ;;
+ m) octave "$file" ;;
+ md) if [ -x "$(command -v lowdown)" ]; then
+ lowdown --parse-no-intraemph "$file" -Tms | groff -mpdfmark -ms -kept -T pdf > "$base".pdf
+ elif [ -x "$(command -v groffdown)" ]; then
+ groffdown -i "$file" | groff -T pdf > "$base".pdf
+ else
+ pandoc -t ms --highlight-style=kate -s -o "$base".pdf "$file"
+ fi ; ;;
+ mom) preconv "$file" | refer -PS -e | groff -mom -kept -T pdf > "$base".pdf ;;
+ ms) preconv "$file" | refer -PS -e | groff -me -ms -kept -T pdf > "$base".pdf ;;
+ org) emacs "$file" --batch -u "$USER" -f org-latex-export-to-pdf ;;
+ py) python "$file" ;;
+ [rR]md) Rscript -e "rmarkdown::render('$file', quiet=TRUE)" ;;
+ rs) cargo build ;;
+ sass) sassc -a "$file" "$base".css ;;
+ scad) openscad -o "$base".stl "$file" ;;
+ sent) setsid -f sent "$file" 2>/dev/null ;;
+ tex) textype "$file" ;;
+ *) sed -n '/^#!/s/^#!//p; q' "$file" | xargs -r -I % "$file" ;;
+esac
diff --git a/.local/bin/cron/README.md b/.local/bin/cron/README.md
new file mode 100644
index 0000000..fa0c354
--- /dev/null
+++ b/.local/bin/cron/README.md
@@ -0,0 +1,11 @@
+# Important Note
+
+These cronjobs have components that require information about your current display to display notifications correctly.
+
+When you add them as cronjobs, I recommend you precede the command with commands as those below:
+
+```
+export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(id -u $USER)/bus; export DISPLAY=:0; . $HOME/.zprofile; then_command_goes_here
+```
+
+This ensures that notifications will display, xdotool commands will function and environmental variables will work as well.
diff --git a/.local/bin/cron/checkup b/.local/bin/cron/checkup
new file mode 100644
index 0000000..bd3c634
--- /dev/null
+++ b/.local/bin/cron/checkup
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+# Syncs repositories and downloads updates, meant to be run as a cronjob.
+
+notify-send "πŸ“¦ Repository Sync" "Checking for package updates..."
+
+sudo pacman -Syyuw --noconfirm || notify-send "Error downloading updates.
+
+Check your internet connection, if pacman is already running, or run update manually to see errors."
+pkill -RTMIN+8 "${STATUSBAR:-dwmblocks}"
+
+if pacman -Qu | grep -v "\[ignored\]"
+then
+ notify-send "🎁 Repository Sync" "Updates available. Click statusbar icon (πŸ“¦) for update."
+else
+ notify-send "πŸ“¦ Repository Sync" "Sync complete. No new packages for update."
+fi
diff --git a/.local/bin/cron/crontog b/.local/bin/cron/crontog
new file mode 100644
index 0000000..c9a640f
--- /dev/null
+++ b/.local/bin/cron/crontog
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# Toggles all cronjobs off/on.
+# Stores disabled crontabs in ~/.config/cronsaved until restored.
+
+([ -f "${XDG_CONFIG_HOME:-$HOME/.config}"/cronsaved ] && crontab - < "${XDG_CONFIG_HOME:-$HOME/.config}"/cronsaved && rm "${XDG_CONFIG_HOME:-$HOME/.config}"/cronsaved && notify-send "πŸ•“ Cronjobs re-enabled.") || ( crontab -l > "${XDG_CONFIG_HOME:-$HOME/.config}"/cronsaved && crontab -r && notify-send "πŸ•“ Cronjobs saved and disabled.")
diff --git a/.local/bin/cron/newsup b/.local/bin/cron/newsup
new file mode 100644
index 0000000..ed266d7
--- /dev/null
+++ b/.local/bin/cron/newsup
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+# Set as a cron job to check for new RSS entries for newsboat.
+# If newsboat is open, sends it an "R" key to refresh.
+
+/usr/bin/notify-send "πŸ“° Updating RSS feeds..."
+
+pgrep -f newsboat$ && /usr/bin/xdotool key --window "$(/usr/bin/xdotool search --name "^newsboat$")" R && exit
+
+echo πŸ”ƒ > /tmp/newsupdate
+pkill -RTMIN+6 "${STATUSBAR:-dwmblocks}"
+/usr/bin/newsboat -x reload
+rm -f /tmp/newsupdate
+pkill -RTMIN+6 "${STATUSBAR:-dwmblocks}"
+/usr/bin/notify-send "πŸ“° RSS feed update complete."
diff --git a/.local/bin/displayselect b/.local/bin/displayselect
new file mode 100755
index 0000000..0227a32
--- /dev/null
+++ b/.local/bin/displayselect
@@ -0,0 +1,82 @@
+#!/bin/sh
+
+# A UI for detecting and selecting all displays. Probes xrandr for connected
+# displays and lets user select one to use. User may also select "manual
+# selection" which opens arandr.
+
+twoscreen() { # If multi-monitor is selected and there are two screens.
+
+ mirror=$(printf "no\\nyes" | dmenu -i -p "Mirror displays?")
+ # Mirror displays using native resolution of external display and a scaled
+ # version for the internal display
+ if [ "$mirror" = "yes" ]; then
+ external=$(echo "$screens" | dmenu -i -p "Optimize resolution for:")
+ internal=$(echo "$screens" | grep -v "$external")
+
+ res_external=$(xrandr --query | sed -n "/^$external/,/\+/p" | \
+ tail -n 1 | awk '{print $1}')
+ res_internal=$(xrandr --query | sed -n "/^$internal/,/\+/p" | \
+ tail -n 1 | awk '{print $1}')
+
+ res_ext_x=$(echo "$res_external" | sed 's/x.*//')
+ res_ext_y=$(echo "$res_external" | sed 's/.*x//')
+ res_int_x=$(echo "$res_internal" | sed 's/x.*//')
+ res_int_y=$(echo "$res_internal" | sed 's/.*x//')
+
+ scale_x=$(echo "$res_ext_x / $res_int_x" | bc -l)
+ scale_y=$(echo "$res_ext_y / $res_int_y" | bc -l)
+
+ xrandr --output "$external" --auto --scale 1.0x1.0 \
+ --output "$internal" --auto --same-as "$external" \
+ --scale "$scale_x"x"$scale_y"
+ else
+
+ primary=$(echo "$screens" | dmenu -i -p "Select primary display:")
+ secondary=$(echo "$screens" | grep -v "$primary")
+ direction=$(printf "left\\nright" | dmenu -i -p "What side of $primary should $secondary be on?")
+ xrandr --output "$primary" --auto --scale 1.0x1.0 --output "$secondary" --"$direction"-of "$primary" --auto --scale 1.0x1.0
+ fi
+ }
+
+morescreen() { # If multi-monitor is selected and there are more than two screens.
+ primary=$(echo "$screens" | dmenu -i -p "Select primary display:")
+ secondary=$(echo "$screens" | grep -v "$primary" | dmenu -i -p "Select secondary display:")
+ direction=$(printf "left\\nright" | dmenu -i -p "What side of $primary should $secondary be on?")
+ tertiary=$(echo "$screens" | grep -v "$primary" | grep -v "$secondary" | dmenu -i -p "Select third display:")
+ xrandr --output "$primary" --auto --output "$secondary" --"$direction"-of "$primary" --auto --output "$tertiary" --"$(printf "left\\nright" | grep -v "$direction")"-of "$primary" --auto
+ }
+
+multimon() { # Multi-monitor handler.
+ case "$(echo "$screens" | wc -l)" in
+ 2) twoscreen ;;
+ *) morescreen ;;
+ esac ;}
+
+onescreen() { # If only one output available or chosen.
+ xrandr --output "$1" --auto --scale 1.0x1.0 $(echo "$allposs" | grep -v "\b$1" | awk '{print "--output", $1, "--off"}' | paste -sd ' ' -)
+ }
+
+postrun() { # Stuff to run to clean up.
+ setbg # Fix background if screen size/arangement has changed.
+ { killall dunst ; setsid -f dunst ;} >/dev/null 2>&1 # Restart dunst to ensure proper location on screen
+ }
+
+# Get all possible displays
+allposs=$(xrandr -q | grep "connected")
+
+# Get all connected screens.
+screens=$(echo "$allposs" | awk '/ connected/ {print $1}')
+
+# If there's only one screen
+[ "$(echo "$screens" | wc -l)" -lt 2 ] &&
+ { onescreen "$screens"; postrun; notify-send "πŸ’» Only one screen detected." "Using it in its optimal settings..."; exit ;}
+
+# Get user choice including multi-monitor and manual selection:
+chosen=$(printf "%s\\nmulti-monitor\\nmanual selection" "$screens" | dmenu -i -p "Select display arangement:") &&
+case "$chosen" in
+ "manual selection") arandr ; exit ;;
+ "multi-monitor") multimon ;;
+ *) onescreen "$chosen" ;;
+esac
+
+postrun
diff --git a/.local/bin/dmenuhandler b/.local/bin/dmenuhandler
new file mode 100755
index 0000000..52960ee
--- /dev/null
+++ b/.local/bin/dmenuhandler
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+# Feed this script a link and it will give dmenu the given choice programs to open it.
+feed="${1:-$(true | dmenu -p 'Paste URL or file path')}"
+
+case "$(printf "copy url\\nnsxiv\\nsetbg\\nPDF\\nbrowser\\nlynx\\nvim\\nmpv\\nmpv loop\\nmpv float\\nqueue download\\nqueue yt-dlp\\nqueue yt-dlp audio" | dmenu -i -p "Open it with?")" in
+ "copy url") echo "$feed" | xclip -selection clipboard ;;
+ mpv) setsid -f mpv -quiet "$feed" >/dev/null 2>&1 ;;
+ "mpv loop") setsid -f mpv -quiet --loop "$feed" >/dev/null 2>&1 ;;
+ "mpv float") setsid -f "$TERMINAL" -e mpv --geometry=+0-0 --autofit=30% --title="mpvfloat" "$feed" >/dev/null 2>&1 ;;
+ "queue yt-dlp") qndl "$feed" >/dev/null 2>&1 ;;
+ "queue yt-dlp audio") qndl "$feed" 'yt-dlp -o "%(title)s.%(ext)s" -f bestaudio --embed-metadata --restrict-filenames' ;;
+ "queue download") qndl "$feed" 'curl -LO' >/dev/null 2>&1 ;;
+ PDF) curl -sL "$feed" > "/tmp/$(echo "$feed" | sed "s|.*/||;s/%20/ /g")" && zathura "/tmp/$(echo "$feed" | sed "s|.*/||;s/%20/ /g")" >/dev/null 2>&1 ;;
+ nsxiv) curl -sL "$feed" > "/tmp/$(echo "$feed" | sed "s|.*/||;s/%20/ /g")" && nsxiv -a "/tmp/$(echo "$feed" | sed "s|.*/||;s/%20/ /g")" >/dev/null 2>&1 ;;
+ vim) curl -sL "$feed" > "/tmp/$(echo "$feed" | sed "s|.*/||;s/%20/ /g")" && setsid -f "$TERMINAL" -e "$EDITOR" "/tmp/$(echo "$feed" | sed "s|.*/||;s/%20/ /g")" >/dev/null 2>&1 ;;
+ setbg) curl -L "$feed" > $XDG_CACHE_HOME/pic ; xwallpaper --zoom $XDG_CACHE_HOME/pic >/dev/null 2>&1 ;;
+ browser) setsid -f "$BROWSER" "$feed" >/dev/null 2>&1 ;;
+ lynx) lynx "$feed" >/dev/null 2>&1 ;;
+esac
diff --git a/.local/bin/dmenupass b/.local/bin/dmenupass
new file mode 100755
index 0000000..2c14e6f
--- /dev/null
+++ b/.local/bin/dmenupass
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# This script is the SUDO_ASKPASS variable, meaning that it will be used as a
+# password prompt if needed.
+
+dmenu -fn Monospace-18 -P -p "$1" <&- && echo
diff --git a/.local/bin/dmenuunicode b/.local/bin/dmenuunicode
new file mode 100755
index 0000000..d438d53
--- /dev/null
+++ b/.local/bin/dmenuunicode
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+# The famous "get a menu of emojis to copy" script.
+
+# Get user selection via dmenu from emoji file.
+chosen=$(cut -d ';' -f1 ~/.local/share/sharks/chars/* | dmenu -i -l 30 | sed "s/ .*//")
+
+# Exit if none chosen.
+[ -z "$chosen" ] && exit
+
+# If you run this command with an argument, it will automatically insert the
+# character. Otherwise, show a message that the emoji has been copied.
+if [ -n "$1" ]; then
+ xdotool type "$chosen"
+else
+ printf "%s" "$chosen" | xclip -selection clipboard
+ notify-send "'$chosen' copied to clipboard." &
+fi
diff --git a/.local/bin/getkeys b/.local/bin/getkeys
new file mode 100755
index 0000000..0705efe
--- /dev/null
+++ b/.local/bin/getkeys
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+cat "${XDG_DATA_HOME:-$HOME/.local/share}"/sharks/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}"/sharks/getkeys
diff --git a/.local/bin/lfub b/.local/bin/lfub
new file mode 100755
index 0000000..83fe974
--- /dev/null
+++ b/.local/bin/lfub
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# lfub:
+# This is a wrapper script for lf 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/.local/bin/linkhandler b/.local/bin/linkhandler
new file mode 100755
index 0000000..d372d84
--- /dev/null
+++ b/.local/bin/linkhandler
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+# Feed script a url or file location.
+# If an image, it will view in nsxiv,
+# 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 [ -z "$1" ]; then
+ url="$(xclip -o)"
+else
+ url="$1"
+fi
+
+case "$url" in
+ *mkv|*webm|*mp4|*youtube.com/watch*|*youtube.com/playlist*|*youtube.com/shorts*|*youtu.be*|*hooktube.com*|*bitchute.com*|*videos.lukesmith.xyz*|*odysee.com*)
+ setsid -f mpv -quiet "$url" >/dev/null 2>&1 ;;
+ *png|*jpg|*jpe|*jpeg|*gif|*webp)
+ curl -sL "$url" > "/tmp/$(echo "$url" | sed "s/.*\///;s/%20/ /g")" && nsxiv -a "/tmp/$(echo "$url" | sed "s/.*\///;s/%20/ /g")" >/dev/null 2>&1 & ;;
+ *pdf|*cbz|*cbr)
+ curl -sL "$url" > "/tmp/$(echo "$url" | sed "s/.*\///;s/%20/ /g")" && zathura "/tmp/$(echo "$url" | sed "s/.*\///;s/%20/ /g")" >/dev/null 2>&1 & ;;
+ *mp3|*flac|*opus|*mp3?source*)
+ qndl "$url" 'curl -LO' >/dev/null 2>&1 ;;
+ *)
+ [ -f "$url" ] && setsid -f "$TERMINAL" -e "$EDITOR" "$url" >/dev/null 2>&1 || setsid -f "$BROWSER" "$url" >/dev/null 2>&1
+esac
diff --git a/.local/bin/maimpick b/.local/bin/maimpick
new file mode 100755
index 0000000..5de26c1
--- /dev/null
+++ b/.local/bin/maimpick
@@ -0,0 +1,18 @@
+#!/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.
+
+# variables
+output="$(date '+%y%m%d-%H%M-%S').png"
+xclip_cmd="xclip -sel clip -t image/png"
+
+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 -u -s pic-selected-"${output}" ;;
+ "current window") maim -q -d 0.2 -i "$(xdotool getactivewindow)" pic-window-"${output}" ;;
+ "full screen") maim -q -d 0.2 pic-full-"${output}" ;;
+ "a selected area (copy)") maim -u -s | ${xclip_cmd} ;;
+ "current window (copy)") maim -q -d 0.2 -i "$(xdotool getactivewindow)" | ${xclip_cmd} ;;
+ "full screen (copy)") maim -q -d 0.2 | ${xclip_cmd} ;;
+esac
diff --git a/.local/bin/mounter b/.local/bin/mounter
new file mode 100755
index 0000000..756d04d
--- /dev/null
+++ b/.local/bin/mounter
@@ -0,0 +1,114 @@
+#!/bin/bash
+
+# Mounts Android Phones and USB drives (encrypted or not). This script will
+# replace the older `dmenumount` which had extra steps and couldn't handle
+# encrypted drives.
+# TODO: Try decrypt for drives in crtypttab
+# TODO: Add some support for connecting iPhones (although they are annoying).
+
+IFS='
+'
+# Function for escaping cell-phone names.
+escape(){ echo "$@" | iconv -cf UTF-8 -t ASCII//TRANSLIT | tr -d '[:punct:]' | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | sed "s/-\+/-/g;s/\(^-\|-\$\)//g" ;}
+
+# Check for phones.
+phones="$(simple-mtpfs -l 2>/dev/null | sed "s/^/πŸ“±/")"
+mountedphones="$(grep "simple-mtpfs" /etc/mtab)"
+# If there are already mounted phones, remove them from the list of mountables.
+[ -n "$mountedphones" ] && phones="$(for phone in $phones; do
+ for mounted in $mountedphones; do
+ escphone="$(escape "$phone")"
+ [[ "$mounted" =~ "$escphone" ]] && break 1
+ done && continue 1
+ echo "$phone"
+done)"
+
+# Check for drives.
+lsblkoutput="$(lsblk -rpo "uuid,name,type,size,label,mountpoint,fstype")"
+# Get all LUKS drives
+allluks="$(echo "$lsblkoutput" | grep crypto_LUKS)"
+# Get a list of the LUKS drive UUIDs already decrypted.
+decrypted="$(find /dev/disk/by-id/dm-uuid-CRYPT-LUKS2-* | sed "s|.*LUKS2-||;s|-.*||")"
+# Functioning for formatting drives correctly for dmenu:
+filter() { sed "s/ /:/g" | awk -F':' '$7==""{printf "%s%s (%s) %s\n",$1,$3,$5,$6}' ; }
+
+# Get only LUKS drives that are not decrypted.
+unopenedluks="$(for drive in $allluks; do
+ uuid="${drive%% *}"
+ uuid="${uuid//-}" # This is a bashism.
+ [ -n "$decrypted" ] && for open in $decrypted; do
+ [ "$uuid" = "$open" ] && break 1
+ done && continue 1
+ echo "πŸ”’ $drive"
+done | filter)"
+
+# Get all normal, non-encrypted or decrypted partitions that are not mounted.
+normalparts="$(echo "$lsblkoutput"| grep -v crypto_LUKS | grep 'part\|rom\|crypt' | sed "s/^/πŸ’Ύ /" | filter )"
+
+# Add all to one variable. If no mountable drives found, exit.
+alldrives="$(echo "$phones
+$unopenedluks
+$normalparts" | sed "/^$/d;s/ *$//")"
+
+# Quit the script if a sequential command fails.
+set -e
+
+test -n "$alldrives"
+
+# Feed all found drives to dmenu and get user choice.
+chosen="$(echo "$alldrives" | dmenu -p "Mount which drive?" -i)"
+
+# Function for prompting user for a mountpoint.
+getmount(){
+ mp="$(find /mnt /media /mount /home -maxdepth 1 -type d 2>/dev/null | dmenu -i -p "Mount this drive where?")"
+ test -n "$mp"
+ if [ ! -d "$mp" ]; then
+ mkdiryn=$(printf "No\\nYes" | dmenu -i -p "$mp does not exist. Create it?")
+ [ "$mkdiryn" = "Yes" ] && (mkdir -p "$mp" || sudo -A mkdir -p "$mp")
+ fi
+}
+
+attemptmount(){
+ # Attempt to mount without a mountpoint, to see if drive is in fstab.
+ sudo -A mount "$chosen" || return 1
+ notify-send "πŸ’ΎDrive Mounted." "$chosen mounted."
+ exit
+}
+
+case "$chosen" in
+ πŸ’Ύ*)
+ chosen="${chosen%% *}"
+ chosen="${chosen:1}" # This is a bashism.
+ attemptmount || getmount
+ sudo -A mount "$chosen" "$mp" -o uid="$(id -u)",gid="$(id -g)"
+ notify-send "πŸ’ΎDrive Mounted." "$chosen mounted to $mp."
+ ;;
+
+ πŸ”’*)
+ chosen="${chosen%% *}"
+ chosen="${chosen:1}" # This is a bashism.
+ # Number the drive.
+ while true; do
+ [ -f "/dev/mapper/usb$num" ] || break
+ num="$(printf "%02d" "$((num +1))")"
+ done
+
+ # Decrypt in a terminal window
+ ${TERMINAL:-st} -n floatterm -g 60x1 -e sudo cryptsetup open "$chosen" "usb$num"
+ # Check if now decrypted.
+ test -b "/dev/mapper/usb$num"
+
+ attemptmount || getmount
+ sudo -A mount "/dev/mapper/usb$num" "$mp" -o uid="$(id -u)",gid="$(id -g)"
+ notify-send "πŸ”“Decrypted drive Mounted." "$chosen decrypted and mounted to $mp."
+ ;;
+
+ πŸ“±*)
+ notify-send "❗Note" "Remember to allow file access on your phone now."
+ getmount
+ number="${chosen%%:*}"
+ number="${chosen:1}" # This is a bashism.
+ sudo -A simple-mtpfs -o allow_other -o fsname="simple-mtpfs-$(escape "$chosen")" --device "$number" "$mp"
+ notify-send "πŸ€– Android Mounted." "Android device mounted to $mp."
+ ;;
+esac
diff --git a/.local/bin/noisereduce b/.local/bin/noisereduce
new file mode 100755
index 0000000..c344760
--- /dev/null
+++ b/.local/bin/noisereduce
@@ -0,0 +1,81 @@
+#!/usr/bin/sh
+
+usage ()
+{
+ printf "Usage : noisereduce <input video file> <output video file>\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/.local/bin/remaps b/.local/bin/remaps
new file mode 100755
index 0000000..fed2965
--- /dev/null
+++ b/.local/bin/remaps
@@ -0,0 +1,14 @@
+#!/bin/sh
+# remaps: This script is called on startup to remap keys.
+
+# Decrease key repeat delay to 300ms and increase key repeat rate to 50 per second.
+xset r rate 300 50
+
+# Map the caps lock key to super, and map the menu key to right super.
+setxkbmap -option caps:super,altwin:menu_win
+
+# When caps lock is pressed only once, treat it as escape.
+killall xcape 2>/dev/null ; xcape -e 'Super_L=Escape'
+
+# Turn off caps lock if on since there is no longer a key for it.
+xset -q | grep -q "Caps Lock:\s*on" && xdotool key Caps_Lock
diff --git a/.local/bin/sbackup b/.local/bin/sbackup
new file mode 100755
index 0000000..1e8c8f4
--- /dev/null
+++ b/.local/bin/sbackup
@@ -0,0 +1,11 @@
+#!/bin/bash
+#
+# Backup Script with rsync
+#
+# Zielverzeichnis fΓΌr das Backup
+BACKUP_DIR="/backup/home_backup"
+
+# Backup mit rsync (komprimiert mit zstd)
+sudo rsync -a --delete --compress --info=progress2 --rsync-path="rsync --compress-level=9" /home/artix/ "$BACKUP_DIR"
+
+echo "Backup abgeschlossen: $BACKUP_DIR"
diff --git a/.local/bin/slider b/.local/bin/slider
new file mode 100755
index 0000000..3460c77
--- /dev/null
+++ b/.local/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:s:" 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/.local/bin/statusbar/sb-battery b/.local/bin/statusbar/sb-battery
new file mode 100755
index 0000000..79030bc
--- /dev/null
+++ b/.local/bin/statusbar/sb-battery
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+# Prints all batteries, their percentage remaining and an emoji corresponding
+# to charge status (πŸ”Œ for plugged up, πŸ”‹ for discharging on battery, etc.).
+
+case $BLOCK_BUTTON in
+ 3) notify-send "πŸ”‹ Battery module" "πŸ”‹: discharging
+πŸ›‘: not charging
+β™»: stagnant charge
+πŸ”Œ: charging
+⚑: charged
+❗: battery very low!
+- Scroll to change adjust xbacklight." ;;
+ 4) xbacklight -inc 10 ;;
+ 5) xbacklight -dec 10 ;;
+ 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+# Loop through all attached batteries and format the info
+for battery in /sys/class/power_supply/BAT?*; do
+ # If non-first battery, print a space separator.
+ [ -n "${capacity+x}" ] && printf " "
+ # Sets up the status and capacity
+ case "$(cat "$battery/status" 2>&1)" in
+ "Full") status="⚑" ;;
+ "Discharging") status="πŸ”‹" ;;
+ "Charging") status="πŸ”Œ" ;;
+ "Not charging") status="πŸ›‘" ;;
+ "Unknown") status="♻️" ;;
+ *) exit 1 ;;
+ esac
+ capacity="$(cat "$battery/capacity" 2>&1)"
+ # Will make a warn variable if discharging and low
+ [ "$status" = "πŸ”‹" ] && [ "$capacity" -le 25 ] && warn="❗"
+ # Prints the info
+ printf "%s%s%d%%" "$status" "$warn" "$capacity"; unset warn
+done && printf "\\n"
diff --git a/.local/bin/statusbar/sb-bluetooth [TODO] b/.local/bin/statusbar/sb-bluetooth [TODO]
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.local/bin/statusbar/sb-bluetooth [TODO]
diff --git a/.local/bin/statusbar/sb-clock b/.local/bin/statusbar/sb-clock
new file mode 100755
index 0000000..572f99d
--- /dev/null
+++ b/.local/bin/statusbar/sb-clock
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+# If you relocate you have to manually change the timezone
+export TZ=Europe/Berlin
+
+clock=$(date '+%I')
+
+case "$clock" in
+ "00") icon="πŸ•›" ;;
+ "01") icon="πŸ•" ;;
+ "02") icon="πŸ•‘" ;;
+ "03") icon="πŸ•’" ;;
+ "04") icon="πŸ•“" ;;
+ "05") icon="πŸ•”" ;;
+ "06") icon="πŸ••" ;;
+ "07") icon="πŸ•–" ;;
+ "08") icon="πŸ•—" ;;
+ "09") icon="πŸ•˜" ;;
+ "10") icon="πŸ•™" ;;
+ "11") icon="πŸ•š" ;;
+ "12") icon="πŸ•›" ;;
+esac
+
+case $BLOCK_BUTTON in
+ 1) notify-send "This Month" "$(cal | sed "s/\<$(date +'%e')\>/<b><span color='red'>&<\/span><\/b>/")" && notify-send "Appointments" "$(calcurse -d3)" ;;
+ 2) setsid -f "$TERMINAL" -e calcurse ;;
+ 3) notify-send "πŸ“… Time/date module" "\- Left click to show upcoming appointments for the next three days via \`calcurse -d3\` and show the month via \`cal\`
+- Middle click opens calcurse if installed" ;;
+ 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+# Ausgabe der Zeit ohne Emoji
+date "+%Y %b %d %a | %I:%M%p"
diff --git a/.local/bin/statusbar/sb-cpu b/.local/bin/statusbar/sb-cpu
new file mode 100755
index 0000000..85e52c8
--- /dev/null
+++ b/.local/bin/statusbar/sb-cpu
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+case $BLOCK_BUTTON in
+ 1) notify-send "πŸ–₯ CPU hogs" "$(ps axch -o cmd:15,%cpu --sort=-%cpu | head)\\n(100% per core)" ;;
+ 2) setsid -f "$TERMINAL" -e htop ;;
+ 3) notify-send "πŸ–₯ CPU module " "\- Shows CPU temperature.
+- Click to show intensive processes.
+- Middle click to open htop." ;;
+ 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+sensors | awk '/Core 0/ {print "" $3 ")" }'
diff --git a/.local/bin/statusbar/sb-cpubars b/.local/bin/statusbar/sb-cpubars
new file mode 100755
index 0000000..4015893
--- /dev/null
+++ b/.local/bin/statusbar/sb-cpubars
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+# Module showing CPU load as a changing bars.
+# Just like in polybar.
+# Each bar represents amount of load on one core since
+# last run.
+
+# Cache in tmpfs to improve speed and reduce SSD load
+cache=/tmp/cpubarscache
+
+case $BLOCK_BUTTON in
+ 2) setsid -f "$TERMINAL" -e htop ;;
+ 3) notify-send "πŸͺ¨ CPU load module" "Each bar represents
+one CPU core";;
+ 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+# id total idle
+stats=$(awk '/cpu[0-9]+/ {printf "%d %d %d\n", substr($1,4), ($2 + $3 + $4 + $5), $5 }' /proc/stat)
+[ ! -f $cache ] && echo "$stats" > "$cache"
+old=$(cat "$cache")
+printf "πŸͺ¨"
+echo "$stats" | while read -r row; do
+ id=${row%% *}
+ rest=${row#* }
+ total=${rest%% *}
+ idle=${rest##* }
+
+ case "$(echo "$old" | awk '{if ($1 == id)
+ printf "%d\n", (1 - (idle - $3) / (total - $2))*100 /12.5}' \
+ id="$id" total="$total" idle="$idle")" in
+
+ "0") printf "▁";;
+ "1") printf "β–‚";;
+ "2") printf "β–ƒ";;
+ "3") printf "β–„";;
+ "4") printf "β–…";;
+ "5") printf "β–†";;
+ "6") printf "β–‡";;
+ "7") printf "β–ˆ";;
+ "8") printf "β–ˆ";;
+ esac
+done; printf "\\n"
+echo "$stats" > "$cache"
diff --git a/.local/bin/statusbar/sb-disk b/.local/bin/statusbar/sb-disk
new file mode 100755
index 0000000..7f3ff79
--- /dev/null
+++ b/.local/bin/statusbar/sb-disk
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+# Status bar module for disk space
+# $1 should be drive mountpoint, otherwise assumed /.
+
+location=${1:-/}
+
+[ -d "$location" ] || exit
+
+case $BLOCK_BUTTON in
+ 1) notify-send "πŸ’½ Disk space" "$(df -h --output=target,used,size)" ;;
+ 3) notify-send "πŸ’½ Disk module" "\- Shows used hard drive space.
+- Click to show all disk info." ;;
+ 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+case "$location" in
+ "/home"* ) icon="🏠" ;;
+ "/mnt"* ) icon="πŸ’Ύ" ;;
+ *) icon="πŸ–₯";;
+esac
+
+printf "%s: %s\n" "$icon" "$(df -h "$location" | awk ' /[0-9]/ {print $3 "/" $2}')"
diff --git a/.local/bin/statusbar/sb-help-icon b/.local/bin/statusbar/sb-help-icon
new file mode 100755
index 0000000..051f663
--- /dev/null
+++ b/.local/bin/statusbar/sb-help-icon
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+# Das anklickbare HilfemenΓΌ. Mittelklick, um den Fenstermanager neu zu starten.
+
+# Überprüfe, ob dwm lÀuft, verwende dwm's Readme und starte neu.
+if pidof dwm >/dev/null; then
+ READMEFILE="/home/artix/.config/sharks/commands.md"
+ restartwm() { pkill -HUP dwm ;}
+else
+ restartwm() { i3 restart ;}
+fi
+
+case $BLOCK_BUTTON in
+ 1) typora "${READMEFILE:-${XDG_DATA_HOME:-$HOME/.local/share}/larbs/readme.md}" ;;
+ 2) restartwm ;;
+ 3) notify-send "❓ Shortcutkeys" ;;
+ 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+echo "❓"
diff --git a/.local/bin/statusbar/sb-internet b/.local/bin/statusbar/sb-internet
new file mode 100755
index 0000000..f94447d
--- /dev/null
+++ b/.local/bin/statusbar/sb-internet
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+# Show wifi πŸ“Ά and percent strength or πŸ“‘ if none.
+# Show 🌐 if connected to ethernet or ❎ if none.
+# Show πŸ”’ if a vpn connection is active
+
+case $BLOCK_BUTTON in
+ 1) "$TERMINAL" -e nmtui; pkill -RTMIN+4 dwmblocks ;;
+ 3) notify-send "🌐 Internet module" "\- Click to connect
+❌: wifi disabled
+πŸ“‘: no wifi connection
+πŸ“Ά: wifi connection with quality
+πŸ›œ: no ethernet
+🌐: ethernet working
+πŸ”’: vpn is active
+" ;;
+ 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+# Wifi
+if [ "$(cat /sys/class/net/w*/operstate 2>/dev/null)" = 'up' ] ; then
+ wifiicon="$(awk '/^\s*w/ { print "πŸ“Ά", int($3 * 100 / 70) "% " }' /proc/net/wireless)"
+elif [ "$(cat /sys/class/net/w*/operstate 2>/dev/null)" = 'down' ] ; then
+ [ "$(cat /sys/class/net/w*/flags 2>/dev/null)" = '0x1003' ] && wifiicon="πŸ“‘ " || wifiicon="❌ "
+fi
+
+# Ethernet
+[ "$(cat /sys/class/net/e*/operstate 2>/dev/null)" = 'up' ] && ethericon="πŸ›œ" || ethericon="πŸ›œ"
+
+# TUN
+[ -n "$(cat /sys/class/net/tun*/operstate 2>/dev/null)" ] && tunicon=" πŸ”’"
+
+printf "%s%s%s\n" "$wifiicon" "$ethericon" "$tunicon"
diff --git a/.local/bin/statusbar/sb-kbselect b/.local/bin/statusbar/sb-kbselect
new file mode 100755
index 0000000..2c58325
--- /dev/null
+++ b/.local/bin/statusbar/sb-kbselect
@@ -0,0 +1,17 @@
+#!/bin/sh
+# works on any init system
+# requirements: dmenu, xorg-setxkbmap
+kb="⌨️" || exit 1
+
+case $BLOCK_BUTTON in
+ 1) kb_choice="$(awk '/! layout/{flag=1; next} /! variant/{flag=0} flag {print $2, "- " $1}' /usr/share/X11/xkb/rules/base.lst | dmenu -l 15)"
+ [ -z "$kb_choice" ] && exit 0
+ kb="$(echo "$kb_choice" | awk '{print "⌨️"}')"
+ setxkbmap "$(echo "$kb_choice" | awk '{print $3}')"
+ pkill -RTMIN+30 "${STATUSBAR:-dwmblocks}";;
+ 3) notify-send "⌨ Keyboard/language module" "$(printf "%s" "\- Current layout: $(setxkbmap -query | grep -oP 'layout:\s*\K\w+')")
+- Left click to change keyboard.";;
+ 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+echo "$kb"
diff --git a/.local/bin/statusbar/sb-mailbox [TODO] b/.local/bin/statusbar/sb-mailbox [TODO]
new file mode 100755
index 0000000..7483aa4
--- /dev/null
+++ b/.local/bin/statusbar/sb-mailbox [TODO]
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+# Displays number of unread mail and an loading icon if updating.
+# When clicked, brings up `neomutt`.
+
+case $BLOCK_BUTTON in
+ 1) setsid -w -f "$TERMINAL" -e neomutt; pkill -RTMIN+12 "${STATUSBAR:-dwmblocks}" ;;
+ 2) setsid -f mw -Y >/dev/null ;;
+ 3) notify-send "πŸ“¬ Mail module" "\- Shows unread mail
+- Shows πŸ”ƒ if syncing mail
+- Left click opens neomutt
+- Middle click syncs mail" ;;
+ 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+unread="$(find "${XDG_DATA_HOME:-$HOME/.local/share}"/mail/*/[Ii][Nn][Bb][Oo][Xx]/new/* -type f | wc -l 2>/dev/null)"
+
+pidof mbsync >/dev/null 2>&1 && icon="πŸ”ƒ"
+
+[ "$unread" = "0" ] && [ "$icon" = "" ] || echo "πŸ“¬$unread$icon"
diff --git a/.local/bin/statusbar/sb-memory b/.local/bin/statusbar/sb-memory
new file mode 100755
index 0000000..1fe74de
--- /dev/null
+++ b/.local/bin/statusbar/sb-memory
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+case $BLOCK_BUTTON in
+ 1) notify-send "🧠 Memory hogs" "$(ps axch -o cmd:15,%mem --sort=-%mem | head)" ;;
+ 2) setsid -f "$TERMINAL" -e htop ;;
+ 3) notify-send "🧠 Memory module" "\- Shows Memory Used/Total.
+- Click to show memory hogs.
+- Middle click to open htop." ;;
+ 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+free --mebi | sed -n '2{p;q}' | awk '{printf "| %2.2fGiB/%2.2fGiB\n", ($3 / 1024), ($2 / 1024)}'
+
diff --git a/.local/bin/statusbar/sb-mpdup b/.local/bin/statusbar/sb-mpdup
new file mode 100755
index 0000000..af81a7d
--- /dev/null
+++ b/.local/bin/statusbar/sb-mpdup
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+# This loop will update the mpd statusbar module whenever a command changes the
+# music player's status. mpd must be running on X's start for this to work.
+
+while : ; do
+ mpc idle >/dev/null && kill -45 "$(pidof "${STATUSBAR:-dwmblocks}")" || break
+done
diff --git a/.local/bin/statusbar/sb-music [TODO] b/.local/bin/statusbar/sb-music [TODO]
new file mode 100755
index 0000000..6734eeb
--- /dev/null
+++ b/.local/bin/statusbar/sb-music [TODO]
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+filter() { sed "/^volume:/d;s/\\[paused\\].*/⏸/g;/\\[playing\\].*/d;/^ERROR/Q" | paste -sd ' ' -;}
+
+pidof -x sb-mpdup >/dev/null 2>&1 || sb-mpdup >/dev/null 2>&1 &
+
+case $BLOCK_BUTTON in
+ 1) mpc status | filter ; setsid -f "$TERMINAL" -e ncmpcpp ;; # right click, pause/unpause
+ 2) mpc toggle | filter ;; # right click, pause/unpause
+ 3) mpc status | filter ; notify-send "🎡 Music module" "\- Shows mpd song playing.
+- ⏸ when paused.
+- Left click opens ncmpcpp.
+- Middle click pauses.
+- Scroll changes track.";; # right click, pause/unpause
+ 4) mpc prev | filter ;; # scroll up, previous
+ 5) mpc next | filter ;; # scroll down, next
+ 6) mpc status | filter ; setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+ *) mpc status | filter ;;
+esac
diff --git a/.local/bin/statusbar/sb-news b/.local/bin/statusbar/sb-news
new file mode 100755
index 0000000..58ff9a9
--- /dev/null
+++ b/.local/bin/statusbar/sb-news
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+# Displays an icon if updating.
+# When clicked, brings up `newsboat`.
+
+case $BLOCK_BUTTON in
+ 1) setsid "$TERMINAL" -e newsboat ;;
+ 2) setsid -f newsup >/dev/null && exit ;;
+ 3) notify-send "\- Shows πŸ”ƒ if updating with \`newsup\`
+- Left click opens newsboat
+- Middle click syncs RSS feeds
+<b>Note:</b> Only one instance of newsboat (including updates) may be running at a time." ;;
+ 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+# Display update icon if updating, otherwise display nothing.
+cat /tmp/newsupdate 2>/dev/null || echo ""
diff --git a/.local/bin/statusbar/sb-pacpackages b/.local/bin/statusbar/sb-pacpackages
new file mode 100755
index 0000000..6acdce6
--- /dev/null
+++ b/.local/bin/statusbar/sb-pacpackages
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+# Displays number of upgradeable packages.
+# For this to work, have a `pacman -Sy` command run in the background as a
+# cronjob every so often as root. This script will then read those packages.
+# When clicked, it will run an upgrade via pacman.
+#
+# Add the following text as a file in /usr/share/libalpm/hooks/statusbar.hook:
+#
+# [Trigger]
+# Operation = Upgrade
+# Type = Package
+# Target = *
+#
+# [Action]
+# Description = Updating statusbar...
+# When = PostTransaction
+# Exec = /usr/bin/pkill -RTMIN+8 dwmblocks # Or i3blocks if using i3.
+
+case $BLOCK_BUTTON in
+ 1) setsid -f "$TERMINAL" -e sb-popupgrade ;;
+ 2) notify-send "$(/usr/bin/pacman -Qu)" ;;
+ 3) notify-send "🎁 Upgrade module" "πŸ“¦: number of upgradable packages
+- Left click to upgrade packages
+- Middle click to show upgradable packages" ;;
+ 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+pacman -Qu | grep -Fcv "[ignored]" | sed "s/^/πŸ“¦/;s/^πŸ“¦0$//g"
diff --git a/.local/bin/statusbar/sb-popupgrade b/.local/bin/statusbar/sb-popupgrade
new file mode 100755
index 0000000..51aa48f
--- /dev/null
+++ b/.local/bin/statusbar/sb-popupgrade
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+printf "Beginning upgrade.\\n"
+
+yay -Syu --noconfirm
+pkill -RTMIN+8 "${STATUSBAR:-dwmblocks}"
+
+printf "\\nUpgrade complete.\\nPress <Enter> to exit window.\\n\\n"
+read -r _
diff --git a/.local/bin/statusbar/sb-tasks [TODO] b/.local/bin/statusbar/sb-tasks [TODO]
new file mode 100755
index 0000000..fbee70b
--- /dev/null
+++ b/.local/bin/statusbar/sb-tasks [TODO]
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+# This block displays the number running background tasks. Requires tsp.
+
+num=$(tsp -l | awk -v numr=0 -v numq=0 '{if (/running/)numr++; if (/queued/)numq++} END{print numr+numq"("numq")"}')
+
+# Handle mouse clicks
+case $BLOCK_BUTTON in
+ 1) setsid -f "$TERMINAL" -e tsp -l ;;
+ 3) notify-send "Tasks module" "πŸ€–: number of running/queued background tasks
+- Left click opens tsp" ;; # Right click
+ 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+[ "$num" != "0(0)" ] &&
+ echo "πŸ€–$num"
diff --git a/.local/bin/statusbar/sb-volume b/.local/bin/statusbar/sb-volume
new file mode 100755
index 0000000..e66dea7
--- /dev/null
+++ b/.local/bin/statusbar/sb-volume
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+# Prints the current volume or πŸ”‡ if muted.
+
+case $BLOCK_BUTTON in
+ 1) setsid -w -f "$TERMINAL" -e pulsemixer; pkill -RTMIN+10 "${STATUSBAR:-dwmblocks}" ;;
+ 2) wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle ;;
+ 4) wpctl set-volume @DEFAULT_AUDIO_SINK@ 1%+ ;;
+ 5) wpctl set-volume @DEFAULT_AUDIO_SINK@ 1%- ;;
+ 3) notify-send "πŸ“’ Volume module" "\- Shows volume πŸ”Š, πŸ”‡ if muted.
+- Middle click to mute.
+- Scroll to change." ;;
+ 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+vol="$(wpctl get-volume @DEFAULT_AUDIO_SINK@)"
+
+# If muted, print πŸ”‡ and exit.
+[ "$vol" != "${vol%\[MUTED\]}" ] && echo πŸ”‡ && exit
+
+vol="${vol#Volume: }"
+
+split() {
+ # For ommiting the . without calling and external program.
+ IFS=$2
+ set -- $1
+ printf '%s' "$@"
+}
+
+vol="$(printf "%.0f" "$(split "$vol" ".")")"
+
+case 1 in
+ $((vol >= 70)) ) icon="πŸ”Š" ;;
+ $((vol >= 30)) ) icon="πŸ”‰" ;;
+ $((vol >= 1)) ) icon="πŸ”ˆ" ;;
+ * ) echo πŸ”‡ && exit ;;
+esac
+
+echo "$icon$vol%"
diff --git a/.local/bin/statusbar/sb-write b/.local/bin/statusbar/sb-write
new file mode 100755
index 0000000..b731626
--- /dev/null
+++ b/.local/bin/statusbar/sb-write
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+# Das anklickbare HilfemenΓΌ. Mittelklick, um den Fenstermanager neu zu starten.
+
+# Überprüfe, ob dwm lÀuft, verwende dwm's Readme und starte neu.
+if pidof dwm >/dev/null; then
+ READMEFILE="/home/artix/Files Sync/πŸ“ Writings/Memoiren/Wer wir sind/Kapitel 1 - Erstes Quartal/βœ”οΈ 1. Kapitel Übersicht.txt"
+ restartwm() { pkill -HUP dwm ;}
+else
+ restartwm() { i3 restart ;}
+fi
+
+case $BLOCK_BUTTON in
+ 1) typora "${READMEFILE:-${XDG_DATA_HOME:-$HOME/.local/share}/larbs/readme.md}" ;;
+ 2) restartwm ;;
+ 3) notify-send "❓ Shortcutkeys" ;;
+ 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+echo "write"
diff --git a/.local/bin/transadd b/.local/bin/transadd
new file mode 100755
index 0000000..a598fad
--- /dev/null
+++ b/.local/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/.local/src/dmenu b/.local/src/dmenu
new file mode 160000
+Subproject c1819f18c07df6984bbfd2ca7207295eec85806
diff --git a/.local/src/dwm b/.local/src/dwm
new file mode 160000
+Subproject 499d9e523a156e55511cee24ac30da9c0c9919f
diff --git a/.local/src/dwmblocks b/.local/src/dwmblocks
new file mode 160000
+Subproject 1c9744ac7ded4fff8171169bc0b9736f3acd4cf
diff --git a/.local/src/st b/.local/src/st
new file mode 160000
+Subproject 36d225d71d448bfe307075580f0d8ef81eeb5a8
diff --git a/.local/src/surf b/.local/src/surf
new file mode 160000
+Subproject 9ef79bf7106496c736ba613c51d2fd5af9d873a