minor updates and addition of personal scripts to local/bin
This commit is contained in:
parent
9ff875b84f
commit
5417494fc3
@ -7,7 +7,7 @@ case $- in
|
|||||||
esac
|
esac
|
||||||
|
|
||||||
export GOPATH="$HOME/go"
|
export GOPATH="$HOME/go"
|
||||||
export PATH="$PATH:$HOME/.local/bin:$GOPATH/bin"
|
export PATH="$PATH:$HOME/.local/bin:$GOPATH/bin:$HOME/scripts"
|
||||||
|
|
||||||
# don't put duplicate lines or lines starting with space in the history.
|
# don't put duplicate lines or lines starting with space in the history.
|
||||||
# See bash(1) for more options
|
# See bash(1) for more options
|
||||||
|
|||||||
@ -178,6 +178,8 @@ map gcxm cd ~/.xmonad
|
|||||||
map gcs cd ~/.config/shell
|
map gcs cd ~/.config/shell
|
||||||
map gcz cd ~/.config/zsh
|
map gcz cd ~/.config/zsh
|
||||||
map gcx1 cd ~/.config/x11
|
map gcx1 cd ~/.config/x11
|
||||||
|
map gll cd ~/.local
|
||||||
|
map glb cd ~/.local/bin
|
||||||
map gw cd ~/work
|
map gw cd ~/work
|
||||||
map gNN cd ~/notes/
|
map gNN cd ~/notes/
|
||||||
map gNw cd ~/notes/zk/work/
|
map gNw cd ~/notes/zk/work/
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
# If you come from bash you might have to change your $PATH.
|
# If you come from bash you might have to change your $PATH.
|
||||||
export GOPATH="$HOME/go"
|
export GOPATH="$HOME/go"
|
||||||
export PATH=$HOME/.local/bin:$GOPATH/bin:$PATH
|
export PATH=$HOME/.local/bin:$GOPATH/bin:$PATH:$HOME/scripts
|
||||||
|
|
||||||
# Path to your oh-my-zsh installation.
|
# Path to your oh-my-zsh installation.
|
||||||
export ZSH="/home/solomon/.oh-my-zsh"
|
export ZSH="/home/solomon/.oh-my-zsh"
|
||||||
|
|||||||
12
.local/bin/bash-status-bat
Executable file
12
.local/bin/bash-status-bat
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
[[ "$(upower -i $(upower -e | grep 'BAT'))" == "" ]] && exit
|
||||||
|
|
||||||
|
current=$(upower -i $(upower -e | grep 'BAT') | grep -E "percentage" | sed 's/.*://' | sed 's/ *//')
|
||||||
|
state=$(upower -i $(upower -e | grep 'BAT') | grep -E "state" | sed 's/.*://' | sed 's/ *//')
|
||||||
|
|
||||||
|
if [[ "$state" == "not charging" ]]; then
|
||||||
|
state="full"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$current $state"
|
||||||
22
.local/bin/bash-status-git
Executable file
22
.local/bin/bash-status-git
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if git status &>/dev/null; then
|
||||||
|
branch=$(git branch --show-current)
|
||||||
|
|
||||||
|
if [ -z "$branch" ]; then
|
||||||
|
echo "(detached)"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
read -ra counts <<< "$(git rev-list --left-right --count "$branch"...origin/"$branch")"
|
||||||
|
to_push=${counts[0]}
|
||||||
|
to_pull=${counts[1]}
|
||||||
|
|
||||||
|
extras=$([[ ${counts[0]} -eq 0 && ${counts[1]} -eq 0 ]] || echo " $to_push↑ $to_pull↓")
|
||||||
|
|
||||||
|
if [[ $(git diff --shortstat 2> /dev/null | tail -n1) != "" ]]; then
|
||||||
|
echo "($branch*$extras)"
|
||||||
|
else
|
||||||
|
echo "($branch~$extras)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
70
.local/bin/bashmatrix
Executable file
70
.local/bin/bashmatrix
Executable file
@ -0,0 +1,70 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Courtesy of @bvierra and company (long ago, pre-cPanel)
|
||||||
|
|
||||||
|
### Customization:
|
||||||
|
blue="\033[0;34m"
|
||||||
|
brightblue="\033[1;34m"
|
||||||
|
cyan="\033[0;36m"
|
||||||
|
brightcyan="\033[1;36m"
|
||||||
|
green="\033[0;32m"
|
||||||
|
brightgreen="\033[1;32m"
|
||||||
|
red="\033[0;31m"
|
||||||
|
brightred="\033[1;31m"
|
||||||
|
white="\033[1;37m"
|
||||||
|
black="\033[0;30m"
|
||||||
|
grey="\033[0;37m"
|
||||||
|
darkgrey="\033[1;30m"
|
||||||
|
# Choose the colors that will be used from the above list
|
||||||
|
# space-separated list
|
||||||
|
# e.g. `colors=($green $brightgreen $darkgrey $white)`
|
||||||
|
colors=($green $brightgreen)
|
||||||
|
### End customization
|
||||||
|
|
||||||
|
### Do not edit below this line
|
||||||
|
spacing=${1:-100} # the likelihood of a character being left in place
|
||||||
|
scroll=${2:-0} # 0 for static, positive integer determines scroll speed
|
||||||
|
screenlines=$(expr `tput lines` - 1 + $scroll)
|
||||||
|
screencols=$(expr `tput cols` / 2 - 1)
|
||||||
|
|
||||||
|
# chars=(a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ^)
|
||||||
|
# charset via Carl:
|
||||||
|
chars=(ア イ ウ エ オ カ キ ク ケ コ サ シ ス セ ソ タ チ ツ テ ト ナ ニ ヌ ネ ノ ハ ヒ フ ヘ ホ マ ミ ム メ モ ヤ ユ ヨ ラ リ ル レ ロ ワ ン)
|
||||||
|
|
||||||
|
count=${#chars[@]}
|
||||||
|
colorcount=${#colors[@]}
|
||||||
|
|
||||||
|
trap "tput sgr0; clear; exit" SIGTERM SIGINT
|
||||||
|
|
||||||
|
if [[ $1 =~ '-h' ]]; then
|
||||||
|
echo "Display a Matrix(ish) screen in the terminal"
|
||||||
|
echo "Usage: matrix [SPACING [SCROLL]]"
|
||||||
|
echo "Example: matrix 100 0"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
clear
|
||||||
|
tput cup 0 0
|
||||||
|
while :
|
||||||
|
do for i in $(eval echo {1..$screenlines})
|
||||||
|
do for i in $(eval echo {1..$screencols})
|
||||||
|
do rand=$(($RANDOM%$spacing))
|
||||||
|
case $rand in
|
||||||
|
0)
|
||||||
|
printf "${colors[$RANDOM%$colorcount]}${chars[$RANDOM%$count]} "
|
||||||
|
;;
|
||||||
|
1)
|
||||||
|
printf " "
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf "\033[2C"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
printf "\n"
|
||||||
|
|
||||||
|
# sleep .005
|
||||||
|
done
|
||||||
|
tput cup 0 0
|
||||||
|
done
|
||||||
29
.local/bin/bw-unlock
Executable file
29
.local/bin/bw-unlock
Executable file
@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
##
|
||||||
|
# Depends: zenity, bw (bitwarden-cli), notify-send
|
||||||
|
#
|
||||||
|
# Generates bw session key and saves it in tmp file where only current user has permissions
|
||||||
|
#
|
||||||
|
# By Solomon Laing (solomonlaing@pm.me)
|
||||||
|
# Date 2020-03-26
|
||||||
|
##
|
||||||
|
|
||||||
|
password=$(zenity --password)
|
||||||
|
|
||||||
|
if [ -z $password ]
|
||||||
|
then
|
||||||
|
exit 0;
|
||||||
|
fi
|
||||||
|
|
||||||
|
session=$(bw unlock "$password" | awk 'NF{last=$NF} END{print last}')
|
||||||
|
|
||||||
|
loc="/tmp/bw-session"
|
||||||
|
|
||||||
|
touch $loc -f
|
||||||
|
|
||||||
|
chmod 600 $loc
|
||||||
|
|
||||||
|
echo "$session" > /tmp/bw-session
|
||||||
|
|
||||||
|
notify-send "Your bitwarden vault has been unlocked until next reboot."
|
||||||
17
.local/bin/checkup
Executable file
17
.local/bin/checkup
Executable file
@ -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
|
||||||
19
.local/bin/cht.sh
Executable file
19
.local/bin/cht.sh
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
commands="rsync find man tldr sed awk tr cp ls grep xargs rg ps mv kill lsof less head tail tar cp rm rename jq cat ssh cargo git git-worktree git-status git-commit git-rebase docker docker-compose stow chmod chown make"
|
||||||
|
|
||||||
|
languages="golang solidity vlang v nodejs javascript tmux typescript zsh cpp c lua rust python bash php haskell ArnoldC css html gdb"
|
||||||
|
|
||||||
|
selected=$(echo "$commands $languages" | tr ' ' '\n' | fzf)
|
||||||
|
if [[ -z $selected ]]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
read -p "Enter Query: " query
|
||||||
|
|
||||||
|
if grep -qs "$selected" "$languages"; then
|
||||||
|
query=$(echo "$query" | tr ' ' '+')
|
||||||
|
tmux neww bash -c "curl cht.sh/$selected/$query & while [ : ]; do sleep 1; done"
|
||||||
|
else
|
||||||
|
tmux neww bash -c "curl -s cht.sh/$selected~$query | less"
|
||||||
|
fi
|
||||||
59
.local/bin/compiler
Executable file
59
.local/bin/compiler
Executable file
@ -0,0 +1,59 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# This script will compile or run another finishing operation on a document. I
|
||||||
|
# have this script run via vim.
|
||||||
|
#
|
||||||
|
# Compiles .tex. groff (.mom, .ms), .rmd, .md, .org. Opens .sent files as sent
|
||||||
|
# presentations. Runs scripts based on extension or shebang.
|
||||||
|
#
|
||||||
|
# Note that .tex files which you wish to compile with XeLaTeX should have the
|
||||||
|
# string "xelatex" somewhere in a comment/command in the first 5 lines.
|
||||||
|
|
||||||
|
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
|
||||||
11
.local/bin/cron/README.md
Normal file
11
.local/bin/cron/README.md
Normal file
@ -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.
|
||||||
17
.local/bin/cron/checkup
Executable file
17
.local/bin/cron/checkup
Executable file
@ -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
|
||||||
6
.local/bin/cron/crontog
Executable file
6
.local/bin/cron/crontog
Executable file
@ -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.")
|
||||||
6
.local/bin/crontog
Executable file
6
.local/bin/crontog
Executable file
@ -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.")
|
||||||
11
.local/bin/dec-sink-volume
Executable file
11
.local/bin/dec-sink-volume
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
default_loc=/tmp/pactl-default-sink
|
||||||
|
|
||||||
|
if [ ! -f "$default_loc" ] ; then
|
||||||
|
set-default-sink
|
||||||
|
fi
|
||||||
|
|
||||||
|
default=$(cat $default_loc)
|
||||||
|
|
||||||
|
pactl set-sink-volume $default -5%
|
||||||
11
.local/bin/dec-source-volume
Executable file
11
.local/bin/dec-source-volume
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
default_loc=/tmp/pactl-default-source
|
||||||
|
|
||||||
|
if [ ! -f "$default_loc" ] ; then
|
||||||
|
set-default-source
|
||||||
|
fi
|
||||||
|
|
||||||
|
default=$(cat $default_loc)
|
||||||
|
|
||||||
|
pactl set-source-volume $default -5%
|
||||||
83
.local/bin/displayselect
Executable file
83
.local/bin/displayselect
Executable file
@ -0,0 +1,83 @@
|
|||||||
|
#!/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.
|
||||||
|
remaps # Re-remap keys if keyboard added (for laptop bases)
|
||||||
|
{ 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
|
||||||
317
.local/bin/dmenu-bluetooth
Executable file
317
.local/bin/dmenu-bluetooth
Executable file
@ -0,0 +1,317 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# _ _ _ _ _ _
|
||||||
|
# __| |_ __ ___ ___ _ __ _ _ | |__ | |_ _ ___| |_ ___ ___ | |_ | |__
|
||||||
|
# / _` | '_ ` _ \ / _ \ '_ \| | | |_____| '_ \| | | | |/ _ \ __/ _ \ / _ \| __|| '_ \
|
||||||
|
# | (_| | | | | | | __/ | | | |_| |_____| |_) | | |_| | __/ || (_) | (_) | |_ | | | |
|
||||||
|
# \__,_|_| |_| |_|\___|_| |_|\__,_| |_.__/|_|\__,_|\___|\__\___/ \___/ \__||_| |_|
|
||||||
|
#
|
||||||
|
# Author: Nick Clyde (clydedroid)
|
||||||
|
# dmenu support by: Layerex
|
||||||
|
#
|
||||||
|
# A script that generates a dmenu menu that uses bluetoothctl to
|
||||||
|
# connect to bluetooth devices and display status info.
|
||||||
|
#
|
||||||
|
# Inspired by networkmanager-dmenu (https://github.com/firecat53/networkmanager-dmenu)
|
||||||
|
# Thanks to x70b1 (https://github.com/polybar/polybar-scripts/tree/master/polybar-scripts/system-bluetooth-bluetoothctl)
|
||||||
|
#
|
||||||
|
# Depends on:
|
||||||
|
# Arch repositories: dmenu, bluez-utils (contains bluetoothctl)
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
divider="---------"
|
||||||
|
goback="Back"
|
||||||
|
|
||||||
|
# Checks if bluetooth controller is powered on
|
||||||
|
power_on() {
|
||||||
|
if bluetoothctl show | grep -F -q "Powered: yes"; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Toggles power state
|
||||||
|
toggle_power() {
|
||||||
|
if power_on; then
|
||||||
|
bluetoothctl power off
|
||||||
|
show_menu
|
||||||
|
else
|
||||||
|
if rfkill list bluetooth | grep -F -q 'blocked: yes'; then
|
||||||
|
rfkill unblock bluetooth && sleep 3
|
||||||
|
fi
|
||||||
|
bluetoothctl power on
|
||||||
|
show_menu
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Checks if controller is scanning for new devices
|
||||||
|
scan_on() {
|
||||||
|
if bluetoothctl show | grep -F -q "Discovering: yes"; then
|
||||||
|
echo "Scan: on"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo "Scan: off"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Toggles scanning state
|
||||||
|
toggle_scan() {
|
||||||
|
if scan_on; then
|
||||||
|
kill "$(pgrep -F -f "bluetoothctl scan on")"
|
||||||
|
bluetoothctl scan off
|
||||||
|
show_menu
|
||||||
|
else
|
||||||
|
bluetoothctl scan on &
|
||||||
|
echo "Scanning..."
|
||||||
|
sleep 5
|
||||||
|
show_menu
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Checks if controller is able to pair to devices
|
||||||
|
pairable_on() {
|
||||||
|
if bluetoothctl show | grep -F -q "Pairable: yes"; then
|
||||||
|
echo "Pairable: on"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo "Pairable: off"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Toggles pairable state
|
||||||
|
toggle_pairable() {
|
||||||
|
if pairable_on; then
|
||||||
|
bluetoothctl pairable off
|
||||||
|
show_menu
|
||||||
|
else
|
||||||
|
bluetoothctl pairable on
|
||||||
|
show_menu
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Checks if controller is discoverable by other devices
|
||||||
|
discoverable_on() {
|
||||||
|
if bluetoothctl show | grep -F -q "Discoverable: yes"; then
|
||||||
|
echo "Discoverable: on"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo "Discoverable: off"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Toggles discoverable state
|
||||||
|
toggle_discoverable() {
|
||||||
|
if discoverable_on; then
|
||||||
|
bluetoothctl discoverable off
|
||||||
|
show_menu
|
||||||
|
else
|
||||||
|
bluetoothctl discoverable on
|
||||||
|
show_menu
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Checks if a device is connected
|
||||||
|
device_connected() {
|
||||||
|
device_info=$(bluetoothctl info "$1")
|
||||||
|
if echo "$device_info" | grep -F -q "Connected: yes"; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Toggles device connection
|
||||||
|
toggle_connection() {
|
||||||
|
if device_connected "$1"; then
|
||||||
|
bluetoothctl disconnect "$1"
|
||||||
|
# device_menu "$device"
|
||||||
|
else
|
||||||
|
bluetoothctl connect "$1"
|
||||||
|
# device_menu "$device"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Checks if a device is paired
|
||||||
|
device_paired() {
|
||||||
|
device_info=$(bluetoothctl info "$1")
|
||||||
|
if echo "$device_info" | grep -F -q "Paired: yes"; then
|
||||||
|
echo "Paired: yes"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo "Paired: no"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Toggles device paired state
|
||||||
|
toggle_paired() {
|
||||||
|
if device_paired "$1"; then
|
||||||
|
bluetoothctl remove "$1"
|
||||||
|
device_menu "$device"
|
||||||
|
else
|
||||||
|
bluetoothctl pair "$1"
|
||||||
|
device_menu "$device"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Checks if a device is trusted
|
||||||
|
device_trusted() {
|
||||||
|
device_info=$(bluetoothctl info "$1")
|
||||||
|
if echo "$device_info" | grep -F -q "Trusted: yes"; then
|
||||||
|
echo "Trusted: yes"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo "Trusted: no"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Toggles device connection
|
||||||
|
toggle_trust() {
|
||||||
|
if device_trusted "$1"; then
|
||||||
|
bluetoothctl untrust "$1"
|
||||||
|
device_menu "$device"
|
||||||
|
else
|
||||||
|
bluetoothctl trust "$1"
|
||||||
|
device_menu "$device"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Prints a short string with the current bluetooth status
|
||||||
|
# Useful for status bars like polybar, etc.
|
||||||
|
print_status() {
|
||||||
|
if power_on; then
|
||||||
|
printf ''
|
||||||
|
|
||||||
|
mapfile -t paired_devices < <(bluetoothctl paired-devices | grep -F Device | cut -d ' ' -f 2)
|
||||||
|
counter=0
|
||||||
|
|
||||||
|
for device in "${paired_devices[@]}"; do
|
||||||
|
if device_connected "$device"; then
|
||||||
|
device_alias="$(bluetoothctl info "$device" | grep -F "Alias" | cut -d ' ' -f 2-)"
|
||||||
|
|
||||||
|
if [ $counter -gt 0 ]; then
|
||||||
|
printf ", %s" "$device_alias"
|
||||||
|
else
|
||||||
|
printf " %s" "$device_alias"
|
||||||
|
fi
|
||||||
|
|
||||||
|
((counter++))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
printf "\n"
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# A submenu for a specific device that allows connecting, pairing, and trusting
|
||||||
|
device_menu() {
|
||||||
|
device=$1
|
||||||
|
|
||||||
|
# Get device name and mac address
|
||||||
|
device_name="$(echo "$device" | cut -d ' ' -f 3-)"
|
||||||
|
mac="$(echo "$device" | cut -d ' ' -f 2)"
|
||||||
|
|
||||||
|
# Build options
|
||||||
|
if device_connected "$mac"; then
|
||||||
|
connected="Connected: yes"
|
||||||
|
else
|
||||||
|
connected="Connected: no"
|
||||||
|
fi
|
||||||
|
paired=$(device_paired "$mac")
|
||||||
|
trusted=$(device_trusted "$mac")
|
||||||
|
options="$connected\n$paired\n$trusted\n$divider\n$goback\nExit"
|
||||||
|
|
||||||
|
# Open dmenu menu, read chosen option
|
||||||
|
chosen="$(echo -e "$options" | run_dmenu "$device_name")"
|
||||||
|
|
||||||
|
# Match chosen option to command
|
||||||
|
case $chosen in
|
||||||
|
"" | "$divider")
|
||||||
|
echo "No option chosen."
|
||||||
|
;;
|
||||||
|
"$connected")
|
||||||
|
toggle_connection "$mac"
|
||||||
|
;;
|
||||||
|
"$paired")
|
||||||
|
toggle_paired "$mac"
|
||||||
|
;;
|
||||||
|
"$trusted")
|
||||||
|
toggle_trust "$mac"
|
||||||
|
;;
|
||||||
|
"$goback")
|
||||||
|
show_menu
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Opens a dmenu menu with current bluetooth status and options to connect
|
||||||
|
show_menu() {
|
||||||
|
# Get menu options
|
||||||
|
if power_on; then
|
||||||
|
power="Power: on"
|
||||||
|
|
||||||
|
# Human-readable names of devices, one per line
|
||||||
|
# If scan is off, will only list paired devices
|
||||||
|
devices=$(bluetoothctl devices | grep -F Device | cut -d ' ' -f 3-)
|
||||||
|
|
||||||
|
# Get controller flags
|
||||||
|
scan=$(scan_on)
|
||||||
|
pairable=$(pairable_on)
|
||||||
|
discoverable=$(discoverable_on)
|
||||||
|
|
||||||
|
# Options passed to dmenu
|
||||||
|
options="$devices\n$divider\n$power\n$scan\n$pairable\n$discoverable\nExit"
|
||||||
|
else
|
||||||
|
power="Power: off"
|
||||||
|
options="$power\nExit"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Open dmenu menu, read chosen option
|
||||||
|
chosen="$(echo -e "$options" | run_dmenu "Bluetooth")"
|
||||||
|
|
||||||
|
# Match chosen option to command
|
||||||
|
case $chosen in
|
||||||
|
"" | "$divider")
|
||||||
|
echo "No option chosen."
|
||||||
|
;;
|
||||||
|
"$power")
|
||||||
|
toggle_power
|
||||||
|
;;
|
||||||
|
"$scan")
|
||||||
|
toggle_scan
|
||||||
|
;;
|
||||||
|
"$discoverable")
|
||||||
|
toggle_discoverable
|
||||||
|
;;
|
||||||
|
"$pairable")
|
||||||
|
toggle_pairable
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
device=$(bluetoothctl devices | grep -F "$chosen")
|
||||||
|
# Open a submenu if a device is selected
|
||||||
|
if [[ $device ]]; then device_menu "$device"; fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
original_args=("$@")
|
||||||
|
|
||||||
|
# dmenu command to pipe into. Extra arguments to dmenu-bluetooth are passed through to dmenu. This
|
||||||
|
# allows the user to set fonts, sizes, colours, etc.
|
||||||
|
run_dmenu() {
|
||||||
|
dmenu "${original_args[@]}" -i -p "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
--status)
|
||||||
|
print_status
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
show_menu
|
||||||
|
;;
|
||||||
|
esac
|
||||||
67
.local/bin/dmenumount
Executable file
67
.local/bin/dmenumount
Executable file
@ -0,0 +1,67 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Gives a dmenu prompt to mount unmounted drives and Android phones. If
|
||||||
|
# they're in /etc/fstab, they'll be mounted automatically. Otherwise, you'll
|
||||||
|
# be prompted to give a mountpoint from already existsing directories. If you
|
||||||
|
# input a novel directory, it will prompt you to create that directory.
|
||||||
|
|
||||||
|
getmount() { \
|
||||||
|
[ -z "$chosen" ] && exit 1
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
mp="$(find $1 2>/dev/null | dmenu -i -p "Type in mount point.")" || exit 1
|
||||||
|
test -z "$mp" && exit 1
|
||||||
|
if [ ! -d "$mp" ]; then
|
||||||
|
mkdiryn=$(printf "No\\nYes" | dmenu -i -p "$mp does not exist. Create it?") || exit 1
|
||||||
|
[ "$mkdiryn" = "Yes" ] && (mkdir -p "$mp" || sudo -A mkdir -p "$mp")
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
mountusb() { \
|
||||||
|
chosen="$(echo "$usbdrives" | dmenu -i -p "Mount which drive?")" || exit 1
|
||||||
|
chosen="$(echo "$chosen" | awk '{print $1}')"
|
||||||
|
sudo -A mount "$chosen" 2>/dev/null && notify-send "💻 USB mounting" "$chosen mounted." && exit 0
|
||||||
|
alreadymounted=$(lsblk -nrpo "name,type,mountpoint" | awk '$3!~/\/boot|\/home$|SWAP/&&length($3)>1{printf "-not ( -path *%s -prune ) ",$3}')
|
||||||
|
getmount "/mnt /media /mount /home -maxdepth 5 -type d $alreadymounted"
|
||||||
|
partitiontype="$(lsblk -no "fstype" "$chosen")"
|
||||||
|
case "$partitiontype" in
|
||||||
|
"vfat") sudo -A mount -t vfat "$chosen" "$mp" -o rw,umask=0000;;
|
||||||
|
"exfat") sudo -A mount "$chosen" "$mp" -o uid="$(id -u)",gid="$(id -g)";;
|
||||||
|
*) sudo -A mount "$chosen" "$mp"; user="$(whoami)"; ug="$(groups | awk '{print $1}')"; sudo -A chown "$user":"$ug" "$mp";;
|
||||||
|
esac && notify-send "💻 USB mounting" "$chosen mounted to $mp." ||
|
||||||
|
notify-send "💻 Drive failed to mount." "Probably a permissions issue or drive is already mounted."
|
||||||
|
}
|
||||||
|
|
||||||
|
mountandroid() { \
|
||||||
|
chosen="$(echo "$anddrives" | dmenu -i -p "Which Android device?")" || exit 1
|
||||||
|
chosen="$(echo "$chosen" | cut -d : -f 1)"
|
||||||
|
getmount "$HOME -maxdepth 3 -type d"
|
||||||
|
echo "OK" | dmenu -i -p "Tap Allow on your phone if it asks for permission and then press enter" || exit 1
|
||||||
|
simple-mtpfs --device "$chosen" "$mp" &&
|
||||||
|
notify-send "🤖 Android Mounting" "Android device mounted to $mp." ||
|
||||||
|
notify-send "🤖 Android failed mounting." "Probably a permissions issue or phone is already mounted."
|
||||||
|
}
|
||||||
|
|
||||||
|
asktype() { \
|
||||||
|
choice="$(printf "USB\\nAndroid" | dmenu -i -p "Mount a USB drive or Android device?")" || exit 1
|
||||||
|
case $choice in
|
||||||
|
USB) mountusb ;;
|
||||||
|
Android) mountandroid ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
anddrives=$(simple-mtpfs -l 2>/dev/null)
|
||||||
|
usbdrives="$(lsblk -rpo "name,type,size,label,mountpoint,fstype" | grep -v crypto_LUKS | grep 'part\|rom' | sed 's/ /:/g' | awk -F':' '$5==""{printf "%s (%s) %s\n",$1,$3,$4}')"
|
||||||
|
|
||||||
|
if [ -z "$usbdrives" ]; then
|
||||||
|
[ -z "$anddrives" ] && echo "No USB drive or Android device detected" && exit
|
||||||
|
echo "Android device(s) detected."
|
||||||
|
mountandroid
|
||||||
|
else
|
||||||
|
if [ -z "$anddrives" ]; then
|
||||||
|
echo "USB drive(s) detected."
|
||||||
|
mountusb
|
||||||
|
else
|
||||||
|
echo "Mountable USB drive(s) and Android device(s) detected."
|
||||||
|
asktype
|
||||||
|
fi
|
||||||
|
fi
|
||||||
19
.local/bin/dmenumountcifs
Executable file
19
.local/bin/dmenumountcifs
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Gives a dmenu prompt to mount unmounted local NAS shares for read/write.
|
||||||
|
# Requirements - "%wheel ALL=(ALL) NOPASSWD: ALL"
|
||||||
|
#
|
||||||
|
# Browse for mDNS/DNS-SD services using the Avahi daemon...
|
||||||
|
srvname=$(avahi-browse _smb._tcp -t | awk '{print $4}' | dmenu -i -p "Which NAS?") || exit 1
|
||||||
|
notify-send "Searching for network shares..." "Please wait..."
|
||||||
|
# Choose share disk...
|
||||||
|
share=$(smbclient -L "$srvname" -N | grep Disk | awk '{print $1}' | dmenu -i -p "Mount which share?") || exit 1
|
||||||
|
# Format URL...
|
||||||
|
share2mnt=//"$srvname".local/"$share"
|
||||||
|
|
||||||
|
sharemount() {
|
||||||
|
mounted=$(mount -v | grep "$share2mnt") || ([ ! -d /mnt/"$share" ] && sudo mkdir /mnt/"$share")
|
||||||
|
[ -z "$mounted" ] && sudo mount -t cifs "$share2mnt" -o user=nobody,password="",noperm /mnt/"$share" && notify-send "Netshare $share mounted" && exit 0
|
||||||
|
notify-send "Netshare $share already mounted"; exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
sharemount
|
||||||
6
.local/bin/dmenupass
Executable file
6
.local/bin/dmenupass
Executable file
@ -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
|
||||||
21
.local/bin/dmenuprompt
Executable file
21
.local/bin/dmenuprompt
Executable file
@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# A dmenu binary prompt script.
|
||||||
|
# Gives a dmenu prompt labelled with $1 to perform command $2.
|
||||||
|
# To invert the options, simply provide a thrid parameter $3.
|
||||||
|
# For example:
|
||||||
|
# `./prompt "Do you want to shutdown?" "shutdown now"`
|
||||||
|
|
||||||
|
# Taken shamelessly from Luke Smith
|
||||||
|
|
||||||
|
if [ -n "$3" ]
|
||||||
|
then
|
||||||
|
choice=$(echo -e "Yes\nNo" | dmenu -bw 0 -i -p "$1")
|
||||||
|
else
|
||||||
|
choice=$(echo -e "No\nYes" | dmenu -bw 0 -i -p "$1")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $choice = "Yes" ]
|
||||||
|
then
|
||||||
|
$2
|
||||||
|
fi
|
||||||
91
.local/bin/dmenusearch
Executable file
91
.local/bin/dmenusearch
Executable file
@ -0,0 +1,91 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Script name: dmenusearch
|
||||||
|
# Description: Search various search engines (inspired by surfraw).
|
||||||
|
# Dependencies: dmenu and a web browser
|
||||||
|
# Usage: dmenusearch <engine>
|
||||||
|
# where engine is amazon, duckduckgo, etc.
|
||||||
|
# without engine all options will be listed
|
||||||
|
|
||||||
|
# Pilfered from Derek Taylor @ https://www.gitlab.com/dwt1/dmscripts
|
||||||
|
|
||||||
|
# Contributors: Derek Taylor
|
||||||
|
# Ali Furkan Yıldız
|
||||||
|
|
||||||
|
# Defining our web browser.
|
||||||
|
DMBROWSER="${BROWSER:-surf}"
|
||||||
|
|
||||||
|
# An array of search engines. You can edit this list to add/remove
|
||||||
|
# search engines. The format must be: "engine_name]="url".
|
||||||
|
# The url format must allow for the search keywords at the end of the url.
|
||||||
|
# For example: https://www.amazon.com/s?k=XXXX searches Amazon for 'XXXX'.
|
||||||
|
declare -A options
|
||||||
|
options[amazon]="https://www.amazon.com/s?k="
|
||||||
|
options[archaur]="https://aur.archlinux.org/packages/?O=0&K="
|
||||||
|
options[archpkg]="https://archlinux.org/packages/?sort=&q="
|
||||||
|
options[archwiki]="https://wiki.archlinux.org/index.php?search="
|
||||||
|
options[arxiv]="https://arxiv.org/search/?searchtype=all&source=header&query="
|
||||||
|
options[bbcnews]="https://www.bbc.co.uk/search?q="
|
||||||
|
options[bing]="https://www.bing.com/search?q="
|
||||||
|
options[cliki]="https://www.cliki.net/site/search?query="
|
||||||
|
options[cnn]="https://www.cnn.com/search?q="
|
||||||
|
options[coinbase]="https://www.coinbase.com/price?query="
|
||||||
|
options[debianpkg]="https://packages.debian.org/search?suite=default§ion=all&arch=any&searchon=names&keywords="
|
||||||
|
options[discogs]="https://www.discogs.com/search/?&type=all&q="
|
||||||
|
options[duckduckgo]="https://duckduckgo.com/?q="
|
||||||
|
options[ebay]="https://www.ebay.com/sch/i.html?&_nkw="
|
||||||
|
options[github]="https://github.com/search?q="
|
||||||
|
options[gitlab]="https://gitlab.com/search?search="
|
||||||
|
options[imdb]="https://www.imdb.com/find?q="
|
||||||
|
options[lbry]="https://lbry.tv/$/search?q="
|
||||||
|
options[odysee]="https://odysee.com/$/search?q="
|
||||||
|
options[reddit]="https://www.reddit.com/search/?q="
|
||||||
|
options[slashdot]="https://slashdot.org/index2.pl?fhfilter="
|
||||||
|
options[socialblade]="https://socialblade.com/youtube/user/"
|
||||||
|
options[sourceforge]="https://sourceforge.net/directory/?q="
|
||||||
|
options[stack]="https://stackoverflow.com/search?q="
|
||||||
|
options[startpage]="https://www.startpage.com/do/dsearch?query="
|
||||||
|
options[stockquote]="https://finance.yahoo.com/quote/"
|
||||||
|
options[thesaurus]="https://www.thesaurus.com/misspelling?term="
|
||||||
|
options[translate]="https://translate.google.com/?sl=auto&tl=en&text="
|
||||||
|
options[urban]="https://www.urbandictionary.com/define.php?term="
|
||||||
|
options[wayback]="https://web.archive.org/web/*/"
|
||||||
|
options[webster]="https://www.merriam-webster.com/dictionary/"
|
||||||
|
options[wikipedia]="https://en.wikipedia.org/wiki/"
|
||||||
|
options[wiktionary]="https://en.wiktionary.org/wiki/"
|
||||||
|
options[wolfram]="https://www.wolframalpha.com/input/?i="
|
||||||
|
options[youtube]="https://www.youtube.com/results?search_query="
|
||||||
|
options[google]="https://www.google.com/search?q="
|
||||||
|
options[googleimages]="https://www.google.com/search?hl=en&tbm=isch&q="
|
||||||
|
options[googlenews]="https://news.google.com/search?q="
|
||||||
|
options[googleSupport]="https://support.google.com/search?q="
|
||||||
|
options[googleSupportAdmin]="https://support.google.com/a/search?q="
|
||||||
|
options[googleStructuredData]="https://search.google.com/structured-data/testing-tool#url="
|
||||||
|
options[googleRichResults]="https://search.google.com/test/rich-results??url="
|
||||||
|
options[googlePagespeed]="https://developers.google.com/speed/pagespeed/insights/?url="
|
||||||
|
options[googleDevelopers]="https://developers.google.com/s/results?q="
|
||||||
|
options[googleOpenSource]="https://opensource.google/projects/search?q="
|
||||||
|
options[googleExperimentswithGoogle]="https://experiments.withgoogle.com/search?q="
|
||||||
|
options[googleDataset]="https://datasetsearch.research.google.com/search?query="
|
||||||
|
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
# Picking a search engine.
|
||||||
|
# shellcheck disable=SC2154
|
||||||
|
while [ -z "$engine" ]; do
|
||||||
|
engine=$(printf '%s\n' "${!options[@]}" | sort | dmenu -i -p 'Choose search engine:') "$@" || exit
|
||||||
|
url="${options["${engine}"]}" || exit
|
||||||
|
done
|
||||||
|
else
|
||||||
|
engine="$1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
url="${options["${engine}"]}" || exit
|
||||||
|
|
||||||
|
# Searching the chosen engine.
|
||||||
|
# shellcheck disable=SC2154
|
||||||
|
while [ -z "$query" ]; do
|
||||||
|
query=$(echo "$engine" | dmenu -p 'Enter search query:') || exit
|
||||||
|
done
|
||||||
|
|
||||||
|
# Display search results in web browser
|
||||||
|
$DMBROWSER "$url""$query"
|
||||||
21
.local/bin/dmenuumount
Executable file
21
.local/bin/dmenuumount
Executable file
@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# A dmenu prompt to unmount drives.
|
||||||
|
# Provides you with mounted partitions, select one to unmount.
|
||||||
|
# Drives mounted at /, /boot and /home will not be options to unmount.
|
||||||
|
|
||||||
|
drives="$(lsblk -nrpo "name,type,size,mountpoint,label" | awk -F':' '{gsub(/ /,":")}$4!~/\/boot|\/efi|\/home$|SWAP/&&length($4)>1{printf "%s (%s) %s\n",$4,$3,$5}'; awk '/simple-mtpfs/ { print "📱", $2; }' /etc/mtab)"
|
||||||
|
|
||||||
|
chosen="$(echo "$drives" | dmenu -i -p "Unmount which drive?")" || exit 1
|
||||||
|
|
||||||
|
case "$chosen" in
|
||||||
|
📱*)
|
||||||
|
chosen="${chosen#📱 }"
|
||||||
|
sudo -A umount -l "$chosen"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
chosen="${chosen% (*}"
|
||||||
|
sudo -A umount -l "$chosen"
|
||||||
|
;;
|
||||||
|
esac && notify-send "🖥️ Drive unmounted." "$chosen successfully unmounted." ||
|
||||||
|
notify-send "🖥️ Drive failed to unmount." "Possibly a permissions or I/O issue."
|
||||||
4
.local/bin/duck
Executable file
4
.local/bin/duck
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
url="https://lite.duckduckgo.com/lite?kd=-1&kp=-1&q=$(urlencode "$*")" # 🦆
|
||||||
|
exec lynx "$url"
|
||||||
45
.local/bin/ext
Executable file
45
.local/bin/ext
Executable file
@ -0,0 +1,45 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# A general, all-purpose extraction script. Not all extraction programs here
|
||||||
|
# are installed by LARBS automatically.
|
||||||
|
#
|
||||||
|
# Default behavior: Extract archive into new directory
|
||||||
|
# Behavior with `-c` option: Extract contents into current directory
|
||||||
|
|
||||||
|
while getopts "hc" o; do case "${o}" in
|
||||||
|
c) extracthere="True" ;;
|
||||||
|
*) printf "Options:\\n -c: Extract archive into current directory rather than a new one.\\n" && exit 1 ;;
|
||||||
|
esac done
|
||||||
|
|
||||||
|
if [ -z "$extracthere" ]; then
|
||||||
|
archive="$(readlink -f "$*")" &&
|
||||||
|
directory="$(echo "$archive" | sed 's/\.[^\/.]*$//')" &&
|
||||||
|
mkdir -p "$directory" &&
|
||||||
|
cd "$directory" || exit 1
|
||||||
|
else
|
||||||
|
archive="$(readlink -f "$(echo "$*" | cut -d' ' -f2)" 2>/dev/null)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -z "$archive" ] && printf "Give archive to extract as argument.\\n" && exit 1
|
||||||
|
|
||||||
|
if [ -f "$archive" ] ; then
|
||||||
|
case "$archive" in
|
||||||
|
*.tar.bz2|*.tbz2) tar xvjf "$archive" ;;
|
||||||
|
*.tar.xz) tar -xf "$archive" ;;
|
||||||
|
*.tar.gz|*.tgz) tar xvzf "$archive" ;;
|
||||||
|
*.tar.zst) tar -I zstd -xf "$archive" ;;
|
||||||
|
*.lzma) unlzma "$archive" ;;
|
||||||
|
*.bz2) bunzip2 "$archive" ;;
|
||||||
|
*.rar) unrar x -ad "$archive" ;;
|
||||||
|
*.gz) gunzip "$archive" ;;
|
||||||
|
*.tar) tar xvf "$archive" ;;
|
||||||
|
*.zip) unzip "$archive" ;;
|
||||||
|
*.Z) uncompress "$archive" ;;
|
||||||
|
*.7z) 7z x "$archive" ;;
|
||||||
|
*.xz) unxz "$archive" ;;
|
||||||
|
*.exe) cabextract "$archive" ;;
|
||||||
|
*) printf "extract: '%s' - unknown archive method\\n" "$archive" ;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
printf "File \"%s\" not found.\\n" "$archive"
|
||||||
|
fi
|
||||||
1449
.local/bin/fishies
Executable file
1449
.local/bin/fishies
Executable file
File diff suppressed because it is too large
Load Diff
12
.local/bin/getcomproot
Executable file
12
.local/bin/getcomproot
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# A helper script for LaTeX/groff files used by `compiler` and `opout`.
|
||||||
|
# The user can add the root file of a larger project as a comment as below:
|
||||||
|
# % root = mainfile.tex
|
||||||
|
# And the compiler script will run on that instead of the opened file.
|
||||||
|
|
||||||
|
texroot="$(grep -i "^.\+\s*root\s*=\s*\S\+" "$1")"
|
||||||
|
texroot="${texroot##*=}"
|
||||||
|
texroot="${texroot//[\"\' ]}"
|
||||||
|
|
||||||
|
[ -f "$texroot" ] && readlink -f "$texroot" || exit 1
|
||||||
103
.local/bin/getnf
Executable file
103
.local/bin/getnf
Executable file
@ -0,0 +1,103 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#defining variables
|
||||||
|
nerdfontsrepo='https://api.github.com/repos/ryanoasis/nerd-fonts'
|
||||||
|
aFontInstalled="False"
|
||||||
|
keepArchives="False"
|
||||||
|
distDir="$HOME/.local/share/fonts"
|
||||||
|
downDir="$HOME/Downloads/NerdFonts"
|
||||||
|
os=$(uname)
|
||||||
|
|
||||||
|
# help message
|
||||||
|
usage() {
|
||||||
|
echo "getNF: A Better way to install NerdFonts"
|
||||||
|
echo ""
|
||||||
|
echo "Usage:"
|
||||||
|
echo "-h print this help message and exit"
|
||||||
|
echo "-k Keep the downloaded archives"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# setting flags
|
||||||
|
while getopts :hk option; do
|
||||||
|
case "${option}" in
|
||||||
|
h) usage && exit 0 ;;
|
||||||
|
k) keepArchives="True" ;;
|
||||||
|
*) usage && exit 0
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# For Macs, need to set a few different things
|
||||||
|
if [[ "$os" == 'Darwin' ]]; then
|
||||||
|
distDir="$HOME/Library/Fonts"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if the distDir and downDir exists, if it doesn't, create it
|
||||||
|
[ -d "$distDir" ] || mkdir -p "$distDir" && echo "Fonts Directory exists, good"
|
||||||
|
[ -d "$downDir" ] || mkdir -p "$downDir" && echo "Download Fonts Directory exists, good"
|
||||||
|
|
||||||
|
# get font names
|
||||||
|
nerdFonts=$(curl --silent "$nerdfontsrepo/contents/patched-fonts?ref=master" | \
|
||||||
|
grep "name" | \
|
||||||
|
awk -F":" '{print $2}' | \
|
||||||
|
sed 's/["",]//g;/install\.ps1/d')
|
||||||
|
|
||||||
|
#get the latest release number from NerdFonts github repo
|
||||||
|
release=$(curl --silent "$nerdfontsrepo/releases/latest" | \
|
||||||
|
grep -Po '"tag_name": "\K.*?(?=")')
|
||||||
|
|
||||||
|
# use fzf to select the fonts to be installed
|
||||||
|
listFonts=$(printf '%s\n' "${nerdFonts[@]}" | fzf -m)
|
||||||
|
|
||||||
|
#loop over the selected fonts in listFonts, download and install them
|
||||||
|
for i in $listFonts; do
|
||||||
|
checkFont=$(fc-list | grep -i "$i")
|
||||||
|
if [ -z "$checkFont" ]; then #If the font already is installed, skip it
|
||||||
|
echo "$i font download started" &&
|
||||||
|
pushd "$downDir" > /dev/null &&
|
||||||
|
#download the font
|
||||||
|
curl -LJO -\# "https://github.com/ryanoasis/nerd-fonts/releases/download/$release/$i.zip" \
|
||||||
|
-o "$i.zip" --create-dirs &&
|
||||||
|
echo "$i font download finished" &&
|
||||||
|
echo "$i font unziping started" &&
|
||||||
|
#Unzipe the downloaded archive
|
||||||
|
# unzip -qq "$downDir/$i.zip" -d "$distDir" &&
|
||||||
|
unzip -qq "$i.zip" -d "$distDir" &&
|
||||||
|
echo "$i font unzipping finished" &&
|
||||||
|
echo "Font $i Installed" &&
|
||||||
|
installedFontName=$(curl --silent "$nerdfontsrepo/contents/patched-fonts/$i/Regular/complete?ref=master" | \
|
||||||
|
grep ".ttf" | \
|
||||||
|
awk -F ":" 'FNR == 1 {print $2}' | \
|
||||||
|
awk '{print $1}' | \
|
||||||
|
sed 's/"//g') &&
|
||||||
|
#set this variable to true so that the font cache get's updated
|
||||||
|
aFontInstalled=True && # We do this before the Additional info, so even if it fails the font cache will be refreshed
|
||||||
|
#Additional info, only if we can get the real font name
|
||||||
|
if [ -n "$installedFontName" ]; then
|
||||||
|
echo "$i provides:" &&
|
||||||
|
fc-list | grep -i "$installedFontName" | \
|
||||||
|
awk -F "/" '{print $7}' | \
|
||||||
|
sed 's/style\=//' | \
|
||||||
|
awk -F ":" 'BEGIN {print "FONT NAME" " | " "FILE NAME" " | " "STYLE"} {print $2 " | " $1 " | " $3}' | \
|
||||||
|
column -s "|" -t
|
||||||
|
fi
|
||||||
|
popd > /dev/null
|
||||||
|
else
|
||||||
|
echo "Font $i already installed"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# If a font was installed, Update the font cache and remove the archive
|
||||||
|
if [ "$aFontInstalled" = "True" ]; then
|
||||||
|
echo "Regenerating fc-cache"
|
||||||
|
fc-cache -f 2>&1 && echo "fc-cache: regeneration succeeded!"
|
||||||
|
#check if the user hasn't chooen to keep the updated, if not, remove them
|
||||||
|
if [ "$keepArchives" = "False" ]; then
|
||||||
|
echo "Removing zip font files in $downDir" &&
|
||||||
|
rm $downDir/*.zip
|
||||||
|
else
|
||||||
|
echo "The archive files are in $downDir"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "All is done!"
|
||||||
4
.local/bin/google
Executable file
4
.local/bin/google
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
url="https://google.com/search?q=$(urlencode "$*")"
|
||||||
|
exec lynx "https://google.com/search?q=$url"
|
||||||
12
.local/bin/ifinstalled
Executable file
12
.local/bin/ifinstalled
Executable file
@ -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
|
||||||
11
.local/bin/inc-sink-volume
Executable file
11
.local/bin/inc-sink-volume
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
default_loc=/tmp/pactl-default-sink
|
||||||
|
|
||||||
|
if [ ! -f "$default_loc" ] ; then
|
||||||
|
set-default-sink
|
||||||
|
fi
|
||||||
|
|
||||||
|
default=$(cat $default_loc)
|
||||||
|
|
||||||
|
pactl set-sink-volume $default +5%
|
||||||
11
.local/bin/inc-source-volume
Executable file
11
.local/bin/inc-source-volume
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
default_loc=/tmp/pactl-default-source
|
||||||
|
|
||||||
|
if [ ! -f "$default_loc" ] ; then
|
||||||
|
set-default-source
|
||||||
|
fi
|
||||||
|
|
||||||
|
default=$(cat $default_loc)
|
||||||
|
|
||||||
|
pactl set-source-volume $default +5%
|
||||||
8
.local/bin/iommu.sh
Executable file
8
.local/bin/iommu.sh
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
shopt -s nullglob
|
||||||
|
for g in /sys/kernel/iommu_groups/*; do
|
||||||
|
echo "IOMMU Group ${g##*/}:"
|
||||||
|
for d in $g/devices/*; do
|
||||||
|
echo -e "\t$(lspci -nns ${d##*/})"
|
||||||
|
done;
|
||||||
|
done;
|
||||||
2
.local/bin/isosec
Executable file
2
.local/bin/isosec
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
exec date -u +%Y%m%d%H%M%S "$@"
|
||||||
26
.local/bin/kbswitcher
Executable file
26
.local/bin/kbswitcher
Executable file
@ -0,0 +1,26 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
fn="/tmp/kbswitcher.status"
|
||||||
|
|
||||||
|
layout=""
|
||||||
|
|
||||||
|
# first run the file won't exist
|
||||||
|
if [ ! -f "$fn" ]; then
|
||||||
|
layout="dvorak"
|
||||||
|
echo "dvorak" > "$fn"
|
||||||
|
else
|
||||||
|
case $(cat "$fn") in
|
||||||
|
us)
|
||||||
|
echo "dvorak" > "$fn"
|
||||||
|
layout="dvorak"
|
||||||
|
;;
|
||||||
|
dvorak)
|
||||||
|
echo "us" > "$fn"
|
||||||
|
layout="us"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
notify-send -u normal -r 161616 "kbswitcher" "Keyboard layout set to $layout."
|
||||||
|
|
||||||
|
setxkbmap -layout "$layout" -option ctrl:nocaps
|
||||||
24
.local/bin/lfub
Executable file
24
.local/bin/lfub
Executable file
@ -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
|
||||||
23
.local/bin/lynx
Executable file
23
.local/bin/lynx
Executable file
@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# be sure to install the ca-certificates package
|
||||||
|
|
||||||
|
lynxpath=/usr/bin/lynx
|
||||||
|
[[ ! -x $lynxpath ]] && lynxpath=/usr/local/bin/lynx
|
||||||
|
|
||||||
|
useragent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.79 Safari/537.1 Lynx"
|
||||||
|
|
||||||
|
if [ -e "$HOME/.config/lynx/lynx.cfg" ];then
|
||||||
|
export LYNX_CFG="$HOME/.config/lynx/lynx.cfg"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -e "$HOME/.config/lynx/lynx.lss" ];then
|
||||||
|
export LYNX_LSS="$HOME/.config/lynx/lynx.lss"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -x "$lynxpath" ]; then
|
||||||
|
echo "Doesn't look like lynx is installed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$lynxpath" --useragent="$useragent" "$@"
|
||||||
18
.local/bin/maimpick
Executable file
18
.local/bin/maimpick
Executable file
@ -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 -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 -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
|
||||||
19
.local/bin/mod_backlight
Executable file
19
.local/bin/mod_backlight
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if command -v brillo &> /dev/null; then
|
||||||
|
function send_notification() {
|
||||||
|
brightness=$(printf "%.0f\n" $(brillo -G))
|
||||||
|
dunstify -a "changebrightness" -u low -r 9991 -h int:value:"$brightness" -i "brightness-$1" "Brightness: $brightness%" -t 2000
|
||||||
|
}
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
up)
|
||||||
|
brillo -A 5 -q -u 150000
|
||||||
|
send_notification $1
|
||||||
|
;;
|
||||||
|
down)
|
||||||
|
brillo -U 5 -q -u 150000
|
||||||
|
send_notification $1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
924
.local/bin/networkmanager_dmenu
Executable file
924
.local/bin/networkmanager_dmenu
Executable file
@ -0,0 +1,924 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# encoding:utf8
|
||||||
|
"""NetworkManager command line dmenu script.
|
||||||
|
|
||||||
|
To add new connections or enable/disable networking requires policykit
|
||||||
|
permissions setup per:
|
||||||
|
https://wiki.archlinux.org/index.php/NetworkManager#Set_up_PolicyKit_permissions
|
||||||
|
|
||||||
|
OR running the script as root
|
||||||
|
|
||||||
|
Add dmenu options and default terminal if desired to
|
||||||
|
~/.config/networkmanager-dmenu/config.ini
|
||||||
|
|
||||||
|
"""
|
||||||
|
import pathlib
|
||||||
|
import struct
|
||||||
|
import configparser
|
||||||
|
import locale
|
||||||
|
import os
|
||||||
|
from os.path import expanduser
|
||||||
|
import shlex
|
||||||
|
from shutil import which
|
||||||
|
import sys
|
||||||
|
from time import sleep
|
||||||
|
import uuid
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
# pylint: disable=import-error
|
||||||
|
import gi
|
||||||
|
gi.require_version('NM', '1.0')
|
||||||
|
from gi.repository import GLib, NM # noqa pylint: disable=wrong-import-position
|
||||||
|
# pylint: enable=import-error
|
||||||
|
|
||||||
|
ENV = os.environ.copy()
|
||||||
|
ENV['LC_ALL'] = 'C'
|
||||||
|
ENC = locale.getpreferredencoding()
|
||||||
|
|
||||||
|
CONF = configparser.ConfigParser()
|
||||||
|
CONF.read(expanduser("~/.config/networkmanager-dmenu/config.ini"))
|
||||||
|
|
||||||
|
|
||||||
|
def cli_args():
|
||||||
|
""" Don't override dmenu_cmd function arguments with CLI args. Removes -l
|
||||||
|
and -p if those are passed on the command line.
|
||||||
|
|
||||||
|
Exception: if -l is passed and dmenu_command is not defined, assume that the
|
||||||
|
user wants to switch dmenu to the vertical layout and include -l.
|
||||||
|
|
||||||
|
Returns: List of additional CLI arguments
|
||||||
|
|
||||||
|
"""
|
||||||
|
args = sys.argv[1:]
|
||||||
|
cmd = CONF.get('dmenu', 'dmenu_command', fallback=False)
|
||||||
|
if "-l" in args or "-p" in args:
|
||||||
|
for nope in ['-l', '-p'] if cmd is not False else ['-p']:
|
||||||
|
try:
|
||||||
|
nope_idx = args.index(nope)
|
||||||
|
del args[nope_idx]
|
||||||
|
del args[nope_idx]
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
return args
|
||||||
|
|
||||||
|
|
||||||
|
def dmenu_pass(command, color):
|
||||||
|
"""Check if dmenu passphrase patch is applied and return the correct command
|
||||||
|
line arg list
|
||||||
|
|
||||||
|
Args: command - string
|
||||||
|
color - obscure color string
|
||||||
|
Returns: list or None
|
||||||
|
|
||||||
|
"""
|
||||||
|
if command != 'dmenu':
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
# Check for dmenu password patch
|
||||||
|
dm_patch = b'P' in subprocess.run(["dmenu", "-h"],
|
||||||
|
capture_output=True,
|
||||||
|
check=False).stderr
|
||||||
|
except FileNotFoundError:
|
||||||
|
dm_patch = False
|
||||||
|
return ["-P"] if dm_patch else ["-nb", color, "-nf", color]
|
||||||
|
|
||||||
|
|
||||||
|
def dmenu_cmd(num_lines, prompt="Networks", active_lines=None):
|
||||||
|
"""Parse config.ini for menu options
|
||||||
|
|
||||||
|
Args: args - num_lines: number of lines to display
|
||||||
|
prompt: prompt to show
|
||||||
|
active_lines: list of line numbers to tag as active
|
||||||
|
Returns: command invocation (as a list of strings) for example
|
||||||
|
["dmenu", "-l", "<num_lines>", "-p", "<prompt>", "-i"]
|
||||||
|
|
||||||
|
"""
|
||||||
|
# Create command string
|
||||||
|
commands = {"dmenu": ["-p", str(prompt)],
|
||||||
|
"rofi": ["-dmenu", "-p", str(prompt), "-l", str(num_lines)],
|
||||||
|
"bemenu": ["-p", str(prompt)],
|
||||||
|
"wofi": ["-p", str(prompt)]}
|
||||||
|
command = shlex.split(CONF.get('dmenu', 'dmenu_command', fallback="dmenu"))
|
||||||
|
command.extend(cli_args())
|
||||||
|
command.extend(commands.get(command[0], []))
|
||||||
|
# Rofi Highlighting
|
||||||
|
rofi_highlight = CONF.getboolean('dmenu', 'rofi_highlight', fallback=False)
|
||||||
|
if rofi_highlight is True and command[0] == "rofi" and active_lines:
|
||||||
|
command.extend(["-a", ",".join([str(num) for num in active_lines])])
|
||||||
|
# Passphrase prompts
|
||||||
|
obscure = CONF.getboolean('dmenu_passphrase', 'obscure', fallback=False)
|
||||||
|
if prompt == "Passphrase" and obscure is True:
|
||||||
|
obscure_color = CONF.get('dmenu_passphrase', 'obscure_color', fallback='#222222')
|
||||||
|
pass_prompts = {"dmenu": dmenu_pass(command[0], obscure_color),
|
||||||
|
"rofi": ['-password'],
|
||||||
|
"bemenu": ['-x'],
|
||||||
|
"wofi": ['-P']}
|
||||||
|
command.extend(pass_prompts.get(command[0], []))
|
||||||
|
return command
|
||||||
|
|
||||||
|
|
||||||
|
def choose_adapter(client):
|
||||||
|
"""If there is more than one wifi adapter installed, ask which one to use
|
||||||
|
|
||||||
|
"""
|
||||||
|
devices = client.get_devices()
|
||||||
|
devices = [i for i in devices if i.get_device_type() == NM.DeviceType.WIFI]
|
||||||
|
if not devices:
|
||||||
|
return None
|
||||||
|
if len(devices) == 1:
|
||||||
|
return devices[0]
|
||||||
|
device_names = "\n".join([d.get_iface() for d in devices])
|
||||||
|
sel = subprocess.run(dmenu_cmd(len(devices), "CHOOSE ADAPTER:"),
|
||||||
|
capture_output=True,
|
||||||
|
check=False,
|
||||||
|
env=ENV,
|
||||||
|
input=device_names,
|
||||||
|
encoding=ENC).stdout
|
||||||
|
if not sel.strip():
|
||||||
|
sys.exit()
|
||||||
|
devices = [i for i in devices if i.get_iface() == sel.strip()]
|
||||||
|
assert len(devices) == 1
|
||||||
|
return devices[0]
|
||||||
|
|
||||||
|
|
||||||
|
def is_installed(cmd):
|
||||||
|
"""Check if a utility is installed"""
|
||||||
|
return which(cmd) is not None
|
||||||
|
|
||||||
|
|
||||||
|
def bluetooth_get_enabled():
|
||||||
|
"""Check if bluetooth is enabled via rfkill.
|
||||||
|
|
||||||
|
Returns None if no bluetooth device was found.
|
||||||
|
"""
|
||||||
|
# See https://www.kernel.org/doc/Documentation/ABI/stable/sysfs-class-rfkill
|
||||||
|
for path in pathlib.Path('/sys/class/rfkill/').glob('rfkill*'):
|
||||||
|
if (path / 'type').read_text().strip() == 'bluetooth':
|
||||||
|
return (path / 'soft').read_text().strip() == '0'
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def create_other_actions(client):
|
||||||
|
"""Return list of other actions that can be taken
|
||||||
|
|
||||||
|
"""
|
||||||
|
networking_enabled = client.networking_get_enabled()
|
||||||
|
networking_action = "Disable" if networking_enabled else "Enable"
|
||||||
|
|
||||||
|
wifi_enabled = client.wireless_get_enabled()
|
||||||
|
wifi_action = "Disable" if wifi_enabled else "Enable"
|
||||||
|
|
||||||
|
bluetooth_enabled = bluetooth_get_enabled()
|
||||||
|
bluetooth_action = "Disable" if bluetooth_enabled else "Enable"
|
||||||
|
|
||||||
|
actions = [Action(f"{wifi_action} Wifi", toggle_wifi,
|
||||||
|
not wifi_enabled),
|
||||||
|
Action(f"{networking_action} Networking",
|
||||||
|
toggle_networking, not networking_enabled)]
|
||||||
|
if bluetooth_enabled is not None:
|
||||||
|
actions.append(Action(f"{bluetooth_action} Bluetooth",
|
||||||
|
toggle_bluetooth, not bluetooth_enabled))
|
||||||
|
actions += [Action("Launch Connection Manager", launch_connection_editor),
|
||||||
|
Action("Delete a Connection", delete_connection)]
|
||||||
|
if wifi_enabled:
|
||||||
|
actions.append(Action("Rescan Wifi Networks", rescan_wifi))
|
||||||
|
return actions
|
||||||
|
|
||||||
|
|
||||||
|
def rescan_wifi():
|
||||||
|
"""
|
||||||
|
Rescan Wifi Access Points
|
||||||
|
"""
|
||||||
|
delay = CONF.getint('nmdm', 'rescan_delay', fallback=5)
|
||||||
|
for dev in CLIENT.get_devices():
|
||||||
|
if gi.repository.NM.DeviceWifi == type(dev):
|
||||||
|
try:
|
||||||
|
dev.request_scan_async(None, rescan_cb, None)
|
||||||
|
LOOP.run()
|
||||||
|
sleep(delay)
|
||||||
|
notify("Wifi scan complete")
|
||||||
|
main()
|
||||||
|
except gi.repository.GLib.Error as err:
|
||||||
|
# Too frequent rescan error
|
||||||
|
notify("Wifi rescan failed", urgency="critical")
|
||||||
|
if not err.code == 6: # pylint: disable=no-member
|
||||||
|
raise err
|
||||||
|
|
||||||
|
|
||||||
|
def rescan_cb(dev, res, data):
|
||||||
|
"""Callback for rescan_wifi. Just for notifications
|
||||||
|
|
||||||
|
"""
|
||||||
|
if dev.request_scan_finish(res) is True:
|
||||||
|
notify("Wifi scan running...")
|
||||||
|
else:
|
||||||
|
notify("Wifi scan failed", urgency="critical")
|
||||||
|
LOOP.quit()
|
||||||
|
|
||||||
|
|
||||||
|
def ssid_to_utf8(nm_ap):
|
||||||
|
""" Convert binary ssid to utf-8 """
|
||||||
|
ssid = nm_ap.get_ssid()
|
||||||
|
if not ssid:
|
||||||
|
return ""
|
||||||
|
ret = NM.utils_ssid_to_utf8(ssid.get_data())
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def prompt_saved(saved_cons):
|
||||||
|
"""Prompt for a saved connection."""
|
||||||
|
actions = create_saved_actions(saved_cons)
|
||||||
|
sel = get_selection(actions)
|
||||||
|
sel()
|
||||||
|
|
||||||
|
|
||||||
|
def ap_security(nm_ap):
|
||||||
|
"""Parse the security flags to return a string with 'WPA2', etc. """
|
||||||
|
flags = nm_ap.get_flags()
|
||||||
|
wpa_flags = nm_ap.get_wpa_flags()
|
||||||
|
rsn_flags = nm_ap.get_rsn_flags()
|
||||||
|
sec_str = ""
|
||||||
|
if ((flags & getattr(NM, '80211ApFlags').PRIVACY) and
|
||||||
|
(wpa_flags == 0) and (rsn_flags == 0)):
|
||||||
|
sec_str = " WEP"
|
||||||
|
if wpa_flags:
|
||||||
|
sec_str = " WPA1"
|
||||||
|
if rsn_flags & getattr(NM, '80211ApSecurityFlags').KEY_MGMT_PSK:
|
||||||
|
sec_str += " WPA2"
|
||||||
|
if rsn_flags & getattr(NM, '80211ApSecurityFlags').KEY_MGMT_SAE:
|
||||||
|
sec_str += " WPA3"
|
||||||
|
if ((wpa_flags & getattr(NM, '80211ApSecurityFlags').KEY_MGMT_802_1X) or
|
||||||
|
(rsn_flags & getattr(NM, '80211ApSecurityFlags').KEY_MGMT_802_1X)):
|
||||||
|
sec_str += " 802.1X"
|
||||||
|
if ((wpa_flags & getattr(NM, '80211ApSecurityFlags').KEY_MGMT_OWE) or
|
||||||
|
(rsn_flags & getattr(NM, '80211ApSecurityFlags').KEY_MGMT_OWE)):
|
||||||
|
sec_str += " OWE"
|
||||||
|
|
||||||
|
# If there is no security use "--"
|
||||||
|
if sec_str == "":
|
||||||
|
sec_str = "--"
|
||||||
|
return sec_str.lstrip()
|
||||||
|
|
||||||
|
|
||||||
|
class Action(): # pylint: disable=too-few-public-methods
|
||||||
|
"""Helper class to execute functions from a string variable"""
|
||||||
|
def __init__(self,
|
||||||
|
name,
|
||||||
|
func,
|
||||||
|
args=None,
|
||||||
|
active=False):
|
||||||
|
self.name = name
|
||||||
|
self.func = func
|
||||||
|
self.is_active = active
|
||||||
|
if args is None:
|
||||||
|
self.args = None
|
||||||
|
elif isinstance(args, list):
|
||||||
|
self.args = args
|
||||||
|
else:
|
||||||
|
self.args = [args]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
if self.args is None:
|
||||||
|
self.func()
|
||||||
|
else:
|
||||||
|
self.func(*self.args)
|
||||||
|
|
||||||
|
|
||||||
|
def conn_matches_adapter(conn, adapter):
|
||||||
|
"""Return True if the connection is applicable for the given adapter.
|
||||||
|
|
||||||
|
There seem to be two ways for a connection specify what interface it belongs
|
||||||
|
to:
|
||||||
|
|
||||||
|
- By setting 'mac-address' in [wifi] to the adapter's MAC
|
||||||
|
- By setting 'interface-name` in [connection] to the adapter's name.
|
||||||
|
|
||||||
|
Depending on how the connection was added, it seems like either
|
||||||
|
'mac-address', 'interface-name' or neither of both is set.
|
||||||
|
"""
|
||||||
|
# [wifi] mac-address
|
||||||
|
setting_wireless = conn.get_setting_wireless()
|
||||||
|
mac = setting_wireless.get_mac_address()
|
||||||
|
if mac is not None:
|
||||||
|
return mac == adapter.get_permanent_hw_address()
|
||||||
|
|
||||||
|
# [connection] interface-name
|
||||||
|
setting_connection = conn.get_setting_connection()
|
||||||
|
interface = setting_connection.get_interface_name()
|
||||||
|
if interface is not None:
|
||||||
|
return interface == adapter.get_iface()
|
||||||
|
|
||||||
|
# Neither is set, let's assume this connection is for multiple/all adapters.
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def process_ap(nm_ap, is_active, adapter):
|
||||||
|
"""Activate/Deactivate a connection and get password if required"""
|
||||||
|
if is_active:
|
||||||
|
CLIENT.deactivate_connection_async(nm_ap, None, deactivate_cb, nm_ap)
|
||||||
|
LOOP.run()
|
||||||
|
else:
|
||||||
|
conns_cur = [i for i in CONNS if
|
||||||
|
i.get_setting_wireless() is not None and
|
||||||
|
conn_matches_adapter(i, adapter)]
|
||||||
|
con = nm_ap.filter_connections(conns_cur)
|
||||||
|
if len(con) > 1:
|
||||||
|
raise ValueError("There are multiple connections possible")
|
||||||
|
|
||||||
|
if len(con) == 1:
|
||||||
|
CLIENT.activate_connection_async(con[0], adapter, nm_ap.get_path(),
|
||||||
|
None, activate_cb, nm_ap)
|
||||||
|
LOOP.run()
|
||||||
|
else:
|
||||||
|
if ap_security(nm_ap) != "--":
|
||||||
|
password = get_passphrase()
|
||||||
|
else:
|
||||||
|
password = ""
|
||||||
|
set_new_connection(nm_ap, password, adapter)
|
||||||
|
|
||||||
|
|
||||||
|
def activate_cb(dev, res, data):
|
||||||
|
"""Notification if activate connection completed successfully
|
||||||
|
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
conn = dev.activate_connection_finish(res)
|
||||||
|
except GLib.Error:
|
||||||
|
conn = None
|
||||||
|
if conn is not None:
|
||||||
|
notify(f"Activated {conn.get_id()}")
|
||||||
|
else:
|
||||||
|
notify(f"Problem activating {data.get_id()}", urgency="critical")
|
||||||
|
LOOP.quit()
|
||||||
|
|
||||||
|
|
||||||
|
def deactivate_cb(dev, res, data):
|
||||||
|
"""Notification if deactivate connection completed successfully
|
||||||
|
|
||||||
|
"""
|
||||||
|
if dev.deactivate_connection_finish(res) is True:
|
||||||
|
notify(f"Deactivated {data.get_id()}")
|
||||||
|
else:
|
||||||
|
notify(f"Problem deactivating {data.get_id()}", urgency="critical")
|
||||||
|
LOOP.quit()
|
||||||
|
|
||||||
|
|
||||||
|
def process_vpngsm(con, activate):
|
||||||
|
"""Activate/deactive VPN or GSM connections"""
|
||||||
|
if activate:
|
||||||
|
CLIENT.activate_connection_async(con, None, None,
|
||||||
|
None, activate_cb, con)
|
||||||
|
else:
|
||||||
|
CLIENT.deactivate_connection_async(con, None, deactivate_cb, con)
|
||||||
|
LOOP.run()
|
||||||
|
|
||||||
|
|
||||||
|
def create_ap_actions(aps, active_ap, active_connection, adapter): # noqa pylint: disable=too-many-locals,line-too-long
|
||||||
|
"""For each AP in a list, create the string and its attached function
|
||||||
|
(activate/deactivate)
|
||||||
|
|
||||||
|
"""
|
||||||
|
active_ap_bssid = active_ap.get_bssid() if active_ap is not None else ""
|
||||||
|
|
||||||
|
names = [ssid_to_utf8(ap) for ap in aps]
|
||||||
|
max_len_name = max([len(name) for name in names]) if names else 0
|
||||||
|
secs = [ap_security(ap) for ap in aps]
|
||||||
|
max_len_sec = max([len(sec) for sec in secs]) if secs else 0
|
||||||
|
|
||||||
|
ap_actions = []
|
||||||
|
|
||||||
|
for nm_ap, name, sec in zip(aps, names, secs):
|
||||||
|
bars = NM.utils_wifi_strength_bars(nm_ap.get_strength())
|
||||||
|
wifi_chars = CONF.get("dmenu", "wifi_chars", fallback=False)
|
||||||
|
if wifi_chars:
|
||||||
|
bars = "".join([wifi_chars[i] for i, j in enumerate(bars) if j == '*'])
|
||||||
|
is_active = nm_ap.get_bssid() == active_ap_bssid
|
||||||
|
compact = CONF.getboolean("dmenu", "compact", fallback=False)
|
||||||
|
if compact:
|
||||||
|
action_name = f"{name} {sec} {bars}"
|
||||||
|
else:
|
||||||
|
action_name = f"{name:<{max_len_name}s} {sec:<{max_len_sec}s} {bars:>4}"
|
||||||
|
if is_active:
|
||||||
|
ap_actions.append(Action(action_name, process_ap,
|
||||||
|
[active_connection, True, adapter],
|
||||||
|
active=True))
|
||||||
|
else:
|
||||||
|
ap_actions.append(Action(action_name, process_ap,
|
||||||
|
[nm_ap, False, adapter]))
|
||||||
|
return ap_actions
|
||||||
|
|
||||||
|
|
||||||
|
def create_vpn_actions(vpns, active):
|
||||||
|
"""Create the list of strings to display with associated function
|
||||||
|
(activate/deactivate) for VPN connections.
|
||||||
|
|
||||||
|
"""
|
||||||
|
active_vpns = [i for i in active if i.get_vpn()]
|
||||||
|
return _create_vpngsm_actions(vpns, active_vpns, "VPN")
|
||||||
|
|
||||||
|
|
||||||
|
def create_wireguard_actions(wgs, active):
|
||||||
|
"""Create the list of strings to display with associated function
|
||||||
|
(activate/deactivate) for Wireguard connections.
|
||||||
|
|
||||||
|
"""
|
||||||
|
active_wgs = [i for i in active if i.get_connection_type() == "wireguard"]
|
||||||
|
return _create_vpngsm_actions(wgs, active_wgs, "Wireguard")
|
||||||
|
|
||||||
|
|
||||||
|
def create_eth_actions(eths, active):
|
||||||
|
"""Create the list of strings to display with associated function
|
||||||
|
(activate/deactivate) for Ethernet connections.
|
||||||
|
|
||||||
|
"""
|
||||||
|
active_eths = [i for i in active if 'ethernet' in i.get_connection_type()]
|
||||||
|
return _create_vpngsm_actions(eths, active_eths, "Eth")
|
||||||
|
|
||||||
|
|
||||||
|
def create_gsm_actions(gsms, active):
|
||||||
|
"""Create the list of strings to display with associated function
|
||||||
|
(activate/deactivate) GSM connections."""
|
||||||
|
active_gsms = [i for i in active if
|
||||||
|
i.get_connection() is not None and
|
||||||
|
i.get_connection().is_type(NM.SETTING_GSM_SETTING_NAME)]
|
||||||
|
return _create_vpngsm_actions(gsms, active_gsms, "GSM")
|
||||||
|
|
||||||
|
|
||||||
|
def create_blue_actions(blues, active):
|
||||||
|
"""Create the list of strings to display with associated function
|
||||||
|
(activate/deactivate) Bluetooth connections."""
|
||||||
|
active_blues = [i for i in active if
|
||||||
|
i.get_connection() is not None and
|
||||||
|
i.get_connection().is_type(NM.SETTING_BLUETOOTH_SETTING_NAME)]
|
||||||
|
return _create_vpngsm_actions(blues, active_blues, "Bluetooth")
|
||||||
|
|
||||||
|
|
||||||
|
def create_saved_actions(saved):
|
||||||
|
"""Create the list of strings to display with associated function
|
||||||
|
(activate/deactivate) for VPN connections.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return _create_vpngsm_actions(saved, [], "SAVED")
|
||||||
|
|
||||||
|
|
||||||
|
def _create_vpngsm_actions(cons, active_cons, label):
|
||||||
|
active_con_ids = [a.get_id() for a in active_cons]
|
||||||
|
actions = []
|
||||||
|
for con in cons:
|
||||||
|
is_active = con.get_id() in active_con_ids
|
||||||
|
action_name = f"{con.get_id()}:{label}"
|
||||||
|
if is_active:
|
||||||
|
active_connection = [a for a in active_cons
|
||||||
|
if a.get_id() == con.get_id()]
|
||||||
|
if len(active_connection) != 1:
|
||||||
|
raise ValueError(f"Multiple active connections match {con.get_id()}")
|
||||||
|
active_connection = active_connection[0]
|
||||||
|
|
||||||
|
actions.append(Action(action_name, process_vpngsm,
|
||||||
|
[active_connection, False], active=True))
|
||||||
|
else:
|
||||||
|
actions.append(Action(action_name, process_vpngsm,
|
||||||
|
[con, True]))
|
||||||
|
return actions
|
||||||
|
|
||||||
|
|
||||||
|
def create_wwan_actions(client):
|
||||||
|
"""Create WWWAN actions
|
||||||
|
|
||||||
|
"""
|
||||||
|
wwan_enabled = client.wwan_get_enabled()
|
||||||
|
wwan_action = "Disable" if wwan_enabled else "Enable"
|
||||||
|
return [Action(f"{wwan_action} WWAN", toggle_wwan, not wwan_enabled)]
|
||||||
|
|
||||||
|
|
||||||
|
def combine_actions(eths, aps, vpns, wgs, gsms, blues, wwan, others, saved):
|
||||||
|
# pylint: disable=too-many-arguments
|
||||||
|
"""Combine all given actions into a list of actions.
|
||||||
|
|
||||||
|
Args: args - eths: list of Actions
|
||||||
|
aps: list of Actions
|
||||||
|
vpns: list of Actions
|
||||||
|
gsms: list of Actions
|
||||||
|
blues: list of Actions
|
||||||
|
wwan: list of Actions
|
||||||
|
others: list of Actions
|
||||||
|
"""
|
||||||
|
compact = CONF.getboolean("dmenu", "compact", fallback=False)
|
||||||
|
empty_action = [Action('', None)] if not compact else []
|
||||||
|
all_actions = []
|
||||||
|
all_actions += eths + empty_action if eths else []
|
||||||
|
all_actions += aps + empty_action if aps else []
|
||||||
|
all_actions += vpns + empty_action if vpns else []
|
||||||
|
all_actions += wgs + empty_action if wgs else []
|
||||||
|
all_actions += gsms + empty_action if (gsms and wwan) else []
|
||||||
|
all_actions += blues + empty_action if blues else []
|
||||||
|
all_actions += wwan + empty_action if wwan else []
|
||||||
|
all_actions += others + empty_action if others else []
|
||||||
|
all_actions += saved + empty_action if saved else []
|
||||||
|
return all_actions
|
||||||
|
|
||||||
|
|
||||||
|
def get_selection(all_actions):
|
||||||
|
"""Spawn dmenu for selection and execute the associated action."""
|
||||||
|
rofi_highlight = CONF.getboolean('dmenu', 'rofi_highlight', fallback=False)
|
||||||
|
inp = []
|
||||||
|
|
||||||
|
if rofi_highlight is True:
|
||||||
|
inp = [str(action) for action in all_actions]
|
||||||
|
else:
|
||||||
|
inp = [('== ' if action.is_active else ' ') + str(action)
|
||||||
|
for action in all_actions]
|
||||||
|
active_lines = [index for index, action in enumerate(all_actions)
|
||||||
|
if action.is_active]
|
||||||
|
|
||||||
|
command = dmenu_cmd(len(inp), active_lines=active_lines)
|
||||||
|
sel = subprocess.run(command,
|
||||||
|
capture_output=True,
|
||||||
|
check=False,
|
||||||
|
input="\n".join(inp),
|
||||||
|
encoding=ENC,
|
||||||
|
env=ENV).stdout
|
||||||
|
|
||||||
|
if not sel.rstrip():
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
if rofi_highlight is False:
|
||||||
|
action = [i for i in all_actions
|
||||||
|
if ((str(i).strip() == str(sel.strip())
|
||||||
|
and not i.is_active) or
|
||||||
|
('== ' + str(i) == str(sel.rstrip('\n'))
|
||||||
|
and i.is_active))]
|
||||||
|
else:
|
||||||
|
action = [i for i in all_actions if str(i).strip() == sel.strip()]
|
||||||
|
assert len(action) == 1, f"Selection was ambiguous: '{str(sel.strip())}'"
|
||||||
|
return action[0]
|
||||||
|
|
||||||
|
|
||||||
|
def toggle_networking(enable):
|
||||||
|
"""Enable/disable networking
|
||||||
|
|
||||||
|
Args: enable - boolean
|
||||||
|
|
||||||
|
"""
|
||||||
|
toggle = GLib.Variant.new_tuple(GLib.Variant.new_boolean(enable))
|
||||||
|
try:
|
||||||
|
CLIENT.dbus_call(NM.DBUS_PATH, NM.DBUS_INTERFACE, "Enable", toggle,
|
||||||
|
None, -1, None, None, None)
|
||||||
|
except AttributeError:
|
||||||
|
# Workaround for older versions of python-gobject
|
||||||
|
CLIENT.networking_set_enabled(enable)
|
||||||
|
notify(f"Networking {'enabled' if enable is True else 'disabled'}")
|
||||||
|
|
||||||
|
|
||||||
|
def toggle_wifi(enable):
|
||||||
|
"""Enable/disable Wifi
|
||||||
|
|
||||||
|
Args: enable - boolean
|
||||||
|
|
||||||
|
"""
|
||||||
|
toggle = GLib.Variant.new_boolean(enable)
|
||||||
|
try:
|
||||||
|
CLIENT.dbus_set_property(NM.DBUS_PATH, NM.DBUS_INTERFACE, "WirelessEnabled", toggle,
|
||||||
|
-1, None, None, None)
|
||||||
|
except AttributeError:
|
||||||
|
# Workaround for older versions of python-gobject
|
||||||
|
CLIENT.wireless_set_enabled(enable)
|
||||||
|
notify(f"Wifi {'enabled' if enable is True else 'disabled'}")
|
||||||
|
|
||||||
|
|
||||||
|
def toggle_wwan(enable):
|
||||||
|
"""Enable/disable WWAN
|
||||||
|
|
||||||
|
Args: enable - boolean
|
||||||
|
|
||||||
|
"""
|
||||||
|
toggle = GLib.Variant.new_boolean(enable)
|
||||||
|
try:
|
||||||
|
CLIENT.dbus_set_property(NM.DBUS_PATH, NM.DBUS_INTERFACE, "WwanEnabled", toggle,
|
||||||
|
-1, None, None, None)
|
||||||
|
except AttributeError:
|
||||||
|
# Workaround for older versions of python-gobject
|
||||||
|
CLIENT.wwan_set_enabled(enable)
|
||||||
|
notify(f"Wwan {'enabled' if enable is True else 'disabled'}")
|
||||||
|
|
||||||
|
|
||||||
|
def toggle_bluetooth(enable):
|
||||||
|
"""Enable/disable Bluetooth
|
||||||
|
|
||||||
|
Args: enable - boolean
|
||||||
|
|
||||||
|
References:
|
||||||
|
https://github.com/blueman-project/blueman/blob/master/blueman/plugins/mechanism/RfKill.py
|
||||||
|
https://www.kernel.org/doc/html/latest/driver-api/rfkill.html
|
||||||
|
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/uapi/linux/rfkill.h?h=v5.8.9
|
||||||
|
|
||||||
|
"""
|
||||||
|
type_bluetooth = 2
|
||||||
|
op_change_all = 3
|
||||||
|
idx = 0
|
||||||
|
soft_state = 0 if enable else 1
|
||||||
|
hard_state = 0
|
||||||
|
|
||||||
|
data = struct.pack("IBBBB", idx, type_bluetooth, op_change_all,
|
||||||
|
soft_state, hard_state)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open('/dev/rfkill', 'r+b', buffering=0) as rff:
|
||||||
|
rff.write(data)
|
||||||
|
except PermissionError:
|
||||||
|
notify("Lacking permission to write to /dev/rfkill.",
|
||||||
|
"Check README for configuration options.",
|
||||||
|
urgency="critical")
|
||||||
|
else:
|
||||||
|
notify(f"Bluetooth {'enabled' if enable else 'disabled'}")
|
||||||
|
|
||||||
|
|
||||||
|
def launch_connection_editor():
|
||||||
|
"""Launch nmtui or the gui nm-connection-editor
|
||||||
|
|
||||||
|
"""
|
||||||
|
terminal = CONF.get("editor", "terminal", fallback="xterm")
|
||||||
|
gui_if_available = CONF.getboolean("editor", "gui_if_available", fallback=True)
|
||||||
|
guis = ["gnome-control-center", "nm-connection-editor"]
|
||||||
|
if gui_if_available is True:
|
||||||
|
for gui in guis:
|
||||||
|
if is_installed(gui):
|
||||||
|
subprocess.run(gui, check=False)
|
||||||
|
return
|
||||||
|
if is_installed("nmtui"):
|
||||||
|
subprocess.run([terminal, "-e", "nmtui"], check=False)
|
||||||
|
return
|
||||||
|
notify("No network connection editor installed", urgency="critical")
|
||||||
|
|
||||||
|
|
||||||
|
def get_passphrase():
|
||||||
|
"""Get a password
|
||||||
|
|
||||||
|
Returns: string
|
||||||
|
|
||||||
|
"""
|
||||||
|
pinentry = CONF.get("dmenu", "pinentry", fallback=None)
|
||||||
|
if pinentry:
|
||||||
|
pin = ""
|
||||||
|
out = subprocess.run(pinentry,
|
||||||
|
capture_output=True,
|
||||||
|
check=False,
|
||||||
|
encoding=ENC,
|
||||||
|
input='setdesc Get network password\ngetpin\n').stdout
|
||||||
|
if out:
|
||||||
|
res = out.split("\n")[2]
|
||||||
|
if res.startswith("D "):
|
||||||
|
pin = res.split("D ")[1]
|
||||||
|
return pin
|
||||||
|
return subprocess.run(dmenu_cmd(0, "Passphrase"),
|
||||||
|
stdin=subprocess.DEVNULL,
|
||||||
|
capture_output=True,
|
||||||
|
check=False,
|
||||||
|
encoding=ENC).stdout
|
||||||
|
|
||||||
|
|
||||||
|
def delete_connection():
|
||||||
|
"""Display list of NM connections and delete the selected one
|
||||||
|
|
||||||
|
"""
|
||||||
|
conn_acts = [Action(i.get_id(), i.delete_async, args=[None, delete_cb, None]) for i in CONNS]
|
||||||
|
conn_names = "\n".join([str(i) for i in conn_acts])
|
||||||
|
sel = subprocess.run(dmenu_cmd(len(conn_acts), "CHOOSE CONNECTION TO DELETE:"),
|
||||||
|
capture_output=True,
|
||||||
|
check=False,
|
||||||
|
input=conn_names,
|
||||||
|
encoding=ENC,
|
||||||
|
env=ENV).stdout
|
||||||
|
if not sel.strip():
|
||||||
|
sys.exit()
|
||||||
|
action = [i for i in conn_acts if str(i) == sel.rstrip("\n")]
|
||||||
|
assert len(action) == 1, f"Selection was ambiguous: {str(sel)}"
|
||||||
|
action[0]()
|
||||||
|
LOOP.run()
|
||||||
|
|
||||||
|
|
||||||
|
def delete_cb(dev, res, data):
|
||||||
|
"""Notification if delete completed successfully
|
||||||
|
|
||||||
|
"""
|
||||||
|
if dev.delete_finish(res) is True:
|
||||||
|
notify(f"Deleted {dev.get_id()}")
|
||||||
|
else:
|
||||||
|
notify(f"Problem deleting {dev.get_id()}", urgency="critical")
|
||||||
|
LOOP.quit()
|
||||||
|
|
||||||
|
|
||||||
|
def set_new_connection(nm_ap, nm_pw, adapter):
|
||||||
|
"""Setup a new NetworkManager connection
|
||||||
|
|
||||||
|
Args: ap - NM.AccessPoint
|
||||||
|
pw - string
|
||||||
|
|
||||||
|
"""
|
||||||
|
nm_pw = str(nm_pw).strip()
|
||||||
|
profile = create_wifi_profile(nm_ap, nm_pw, adapter)
|
||||||
|
CLIENT.add_and_activate_connection_async(profile, adapter, nm_ap.get_path(),
|
||||||
|
None, verify_conn, profile)
|
||||||
|
LOOP.run()
|
||||||
|
|
||||||
|
|
||||||
|
def create_wifi_profile(nm_ap, password, adapter):
|
||||||
|
# pylint: disable=line-too-long
|
||||||
|
# noqa From https://cgit.freedesktop.org/NetworkManager/NetworkManager/tree/examples/python/gi/add_connection.py
|
||||||
|
# noqa and https://cgit.freedesktop.org/NetworkManager/NetworkManager/tree/examples/python/dbus/add-wifi-psk-connection.py
|
||||||
|
# pylint: enable=line-too-long
|
||||||
|
"""Create the NM profile given the AP and passphrase"""
|
||||||
|
ap_sec = ap_security(nm_ap)
|
||||||
|
profile = NM.SimpleConnection.new()
|
||||||
|
|
||||||
|
s_con = NM.SettingConnection.new()
|
||||||
|
s_con.set_property(NM.SETTING_CONNECTION_ID, ssid_to_utf8(nm_ap))
|
||||||
|
s_con.set_property(NM.SETTING_CONNECTION_UUID, str(uuid.uuid4()))
|
||||||
|
s_con.set_property(NM.SETTING_CONNECTION_TYPE, "802-11-wireless")
|
||||||
|
profile.add_setting(s_con)
|
||||||
|
|
||||||
|
s_wifi = NM.SettingWireless.new()
|
||||||
|
s_wifi.set_property(NM.SETTING_WIRELESS_SSID, nm_ap.get_ssid())
|
||||||
|
s_wifi.set_property(NM.SETTING_WIRELESS_MODE, 'infrastructure')
|
||||||
|
s_wifi.set_property(NM.SETTING_WIRELESS_MAC_ADDRESS, adapter.get_permanent_hw_address())
|
||||||
|
profile.add_setting(s_wifi)
|
||||||
|
|
||||||
|
s_ip4 = NM.SettingIP4Config.new()
|
||||||
|
s_ip4.set_property(NM.SETTING_IP_CONFIG_METHOD, "auto")
|
||||||
|
profile.add_setting(s_ip4)
|
||||||
|
|
||||||
|
s_ip6 = NM.SettingIP6Config.new()
|
||||||
|
s_ip6.set_property(NM.SETTING_IP_CONFIG_METHOD, "auto")
|
||||||
|
profile.add_setting(s_ip6)
|
||||||
|
|
||||||
|
if ap_sec != "--":
|
||||||
|
s_wifi_sec = NM.SettingWirelessSecurity.new()
|
||||||
|
if "WPA" in ap_sec:
|
||||||
|
if "WPA3" in ap_sec:
|
||||||
|
s_wifi_sec.set_property(NM.SETTING_WIRELESS_SECURITY_KEY_MGMT,
|
||||||
|
"sae")
|
||||||
|
else:
|
||||||
|
s_wifi_sec.set_property(NM.SETTING_WIRELESS_SECURITY_KEY_MGMT,
|
||||||
|
"wpa-psk")
|
||||||
|
s_wifi_sec.set_property(NM.SETTING_WIRELESS_SECURITY_AUTH_ALG,
|
||||||
|
"open")
|
||||||
|
s_wifi_sec.set_property(NM.SETTING_WIRELESS_SECURITY_PSK, password)
|
||||||
|
elif "WEP" in ap_sec:
|
||||||
|
s_wifi_sec.set_property(NM.SETTING_WIRELESS_SECURITY_KEY_MGMT,
|
||||||
|
"None")
|
||||||
|
s_wifi_sec.set_property(NM.SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE,
|
||||||
|
NM.WepKeyType.PASSPHRASE)
|
||||||
|
s_wifi_sec.set_wep_key(0, password)
|
||||||
|
profile.add_setting(s_wifi_sec)
|
||||||
|
|
||||||
|
return profile
|
||||||
|
|
||||||
|
|
||||||
|
def verify_conn(client, result, data):
|
||||||
|
"""Callback function for add_and_activate_connection_async
|
||||||
|
|
||||||
|
Check if connection completes successfully. Delete the connection if there
|
||||||
|
is an error.
|
||||||
|
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
act_conn = client.add_and_activate_connection_finish(result)
|
||||||
|
conn = act_conn.get_connection()
|
||||||
|
if not all([conn.verify(),
|
||||||
|
conn.verify_secrets(),
|
||||||
|
data.verify(),
|
||||||
|
data.verify_secrets()]):
|
||||||
|
raise GLib.Error
|
||||||
|
notify(f"Added {conn.get_id()}")
|
||||||
|
except GLib.Error:
|
||||||
|
try:
|
||||||
|
notify(f"Connection to {conn.get_id()} failed",
|
||||||
|
urgency="critical")
|
||||||
|
conn.delete_async(None, None, None)
|
||||||
|
except UnboundLocalError:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
LOOP.quit()
|
||||||
|
|
||||||
|
|
||||||
|
def create_ap_list(adapter, active_connections):
|
||||||
|
"""Generate list of access points. Remove duplicate APs , keeping strongest
|
||||||
|
ones and the active AP
|
||||||
|
|
||||||
|
Args: adapter
|
||||||
|
active_connections - list of all active connections
|
||||||
|
Returns: aps - list of access points
|
||||||
|
active_ap - active AP
|
||||||
|
active_ap_con - active Connection
|
||||||
|
adapter
|
||||||
|
|
||||||
|
"""
|
||||||
|
aps = []
|
||||||
|
ap_names = []
|
||||||
|
active_ap = adapter.get_active_access_point()
|
||||||
|
aps_all = sorted(adapter.get_access_points(),
|
||||||
|
key=lambda a: a.get_strength(), reverse=True)
|
||||||
|
conns_cur = [i for i in CONNS if
|
||||||
|
i.get_setting_wireless() is not None and
|
||||||
|
conn_matches_adapter(i, adapter)]
|
||||||
|
try:
|
||||||
|
ap_conns = active_ap.filter_connections(conns_cur)
|
||||||
|
active_ap_name = ssid_to_utf8(active_ap)
|
||||||
|
active_ap_con = [active_conn for active_conn in active_connections
|
||||||
|
if active_conn.get_connection() in ap_conns]
|
||||||
|
except AttributeError:
|
||||||
|
active_ap_name = None
|
||||||
|
active_ap_con = []
|
||||||
|
if len(active_ap_con) > 1:
|
||||||
|
raise ValueError("Multiple connection profiles match"
|
||||||
|
" the wireless AP")
|
||||||
|
active_ap_con = active_ap_con[0] if active_ap_con else None
|
||||||
|
for nm_ap in aps_all:
|
||||||
|
ap_name = ssid_to_utf8(nm_ap)
|
||||||
|
if nm_ap != active_ap and ap_name == active_ap_name:
|
||||||
|
# Skip adding AP if it's not active but same name as active AP
|
||||||
|
continue
|
||||||
|
if ap_name not in ap_names:
|
||||||
|
ap_names.append(ap_name)
|
||||||
|
aps.append(nm_ap)
|
||||||
|
return aps, active_ap, active_ap_con, adapter
|
||||||
|
|
||||||
|
|
||||||
|
def notify(message, details=None, urgency="low"):
|
||||||
|
"""Use notify-send if available for notifications
|
||||||
|
|
||||||
|
"""
|
||||||
|
delay = CONF.getint('nmdm', 'rescan_delay', fallback=5)
|
||||||
|
args = ["-u", urgency, "-a", "networkmanager-dmenu",
|
||||||
|
"-t", str(delay * 1000), message]
|
||||||
|
if details is not None:
|
||||||
|
args.append(details)
|
||||||
|
if is_installed("notify-send"):
|
||||||
|
subprocess.run(["notify-send"] + args, check=False)
|
||||||
|
|
||||||
|
|
||||||
|
def run(): # pylint: disable=too-many-locals
|
||||||
|
"""Main script entrypoint"""
|
||||||
|
active = CLIENT.get_active_connections()
|
||||||
|
adapter = choose_adapter(CLIENT)
|
||||||
|
if adapter:
|
||||||
|
ap_actions = create_ap_actions(*create_ap_list(adapter, active))
|
||||||
|
else:
|
||||||
|
ap_actions = []
|
||||||
|
|
||||||
|
vpns = [i for i in CONNS if i.is_type(NM.SETTING_VPN_SETTING_NAME)]
|
||||||
|
try:
|
||||||
|
wgs = [i for i in CONNS if i.is_type(NM.SETTING_WIREGUARD_SETTING_NAME)]
|
||||||
|
except AttributeError:
|
||||||
|
# Workaround for older versions of python-gobject with no wireguard support
|
||||||
|
wgs = []
|
||||||
|
eths = [i for i in CONNS if i.is_type(NM.SETTING_WIRED_SETTING_NAME)]
|
||||||
|
blues = [i for i in CONNS if i.is_type(NM.SETTING_BLUETOOTH_SETTING_NAME)]
|
||||||
|
|
||||||
|
vpn_actions = create_vpn_actions(vpns, active)
|
||||||
|
wg_actions = create_wireguard_actions(wgs, active)
|
||||||
|
eth_actions = create_eth_actions(eths, active)
|
||||||
|
blue_actions = create_blue_actions(blues, active)
|
||||||
|
other_actions = create_other_actions(CLIENT)
|
||||||
|
wwan_installed = is_installed("ModemManager")
|
||||||
|
if wwan_installed:
|
||||||
|
gsms = [i for i in CONNS if i.is_type(NM.SETTING_GSM_SETTING_NAME)]
|
||||||
|
gsm_actions = create_gsm_actions(gsms, active)
|
||||||
|
wwan_actions = create_wwan_actions(CLIENT)
|
||||||
|
else:
|
||||||
|
gsm_actions = []
|
||||||
|
wwan_actions = []
|
||||||
|
|
||||||
|
list_saved = CONF.getboolean('dmenu', 'list_saved', fallback=False)
|
||||||
|
saved_cons = [i for i in CONNS if i not in vpns + wgs + eths + blues]
|
||||||
|
if list_saved:
|
||||||
|
saved_actions = create_saved_actions(saved_cons)
|
||||||
|
else:
|
||||||
|
saved_actions = [Action("Saved connections", prompt_saved, [saved_cons])]
|
||||||
|
|
||||||
|
actions = combine_actions(eth_actions, ap_actions, vpn_actions, wg_actions,
|
||||||
|
gsm_actions, blue_actions, wwan_actions,
|
||||||
|
other_actions, saved_actions)
|
||||||
|
sel = get_selection(actions)
|
||||||
|
sel()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main. Enables script to be re-run after a wifi rescan
|
||||||
|
|
||||||
|
"""
|
||||||
|
global CLIENT, CONNS, LOOP # noqa pylint: disable=global-variable-undefined
|
||||||
|
CLIENT = NM.Client.new(None)
|
||||||
|
LOOP = GLib.MainLoop()
|
||||||
|
CONNS = CLIENT.get_connections()
|
||||||
|
|
||||||
|
run()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
||||||
|
# vim: set et ts=4 sw=4 :
|
||||||
13
.local/bin/opout
Executable file
13
.local/bin/opout
Executable file
@ -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|*.sil|*.m[dse]|*.[rR]md|*.mom|*.[0-9]) target="$(getcomproot "$1" || echo "$1")" ; setsid -f xdg-open "${target%.*}".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
|
||||||
12
.local/bin/rotdir
Executable file
12
.local/bin/rotdir
Executable file
@ -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; }'
|
||||||
18
.local/bin/rssadd
Executable file
18
.local/bin/rssadd
Executable file
@ -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
|
||||||
16
.local/bin/screenlayout
Executable file
16
.local/bin/screenlayout
Executable file
@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
layouts=($(ls "$HOME/.screenlayout/"))
|
||||||
|
|
||||||
|
add="add layout..."
|
||||||
|
|
||||||
|
layouts+=("$add")
|
||||||
|
|
||||||
|
choice=$( printf '%s\n' "${layouts[@]}" | dmenu -i -p 'Choose a screenlayout:') "$@" || exit
|
||||||
|
|
||||||
|
if [ "$choice" = "$add" ]
|
||||||
|
then
|
||||||
|
arandr &
|
||||||
|
else
|
||||||
|
exec "$HOME/.screenlayout/$choice"
|
||||||
|
fi
|
||||||
13
.local/bin/screenshot
Executable file
13
.local/bin/screenshot
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
SCRIPTNAME=$(basename $0)
|
||||||
|
FILENAME="$HOME/$SCRIPTNAME-$(date +'%Y-%m-%d-%H-%M-%S').png"
|
||||||
|
|
||||||
|
case ${1:-} in
|
||||||
|
select*|region|area) SEL="-s" ;;
|
||||||
|
*) SEL="" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
maim --format=png $SEL "$FILENAME"
|
||||||
|
echo -n $FILENAME | xclip -selection clipbard
|
||||||
|
notify-send "Screenshot" "$(echo -e "Screen shot saved\n$FILENAME")"
|
||||||
13
.local/bin/set-default-sink
Executable file
13
.local/bin/set-default-sink
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
choice=$(pactl list short sinks | awk '{print $2}' | dmenu -i -p "which sink should be default?")
|
||||||
|
|
||||||
|
if [ -z "$choice" ] ; then
|
||||||
|
exit 0;
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
rm /tmp/pactl-default-sink --force # to ignore if it isn't there
|
||||||
|
touch /tmp/pactl-default-sink
|
||||||
|
echo "$choice" > /tmp/pactl-default-sink
|
||||||
|
pactl set-default-sink $choice # make sure that the chosen sink is the
|
||||||
13
.local/bin/set-default-source
Executable file
13
.local/bin/set-default-source
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
choice=$(pactl list short sources | awk '{print $2}' | dmenu -i -p "which source should be default?")
|
||||||
|
|
||||||
|
if [ -z "$choice" ] ; then
|
||||||
|
exit 0;
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
rm /tmp/pactl-default-source --force # to ignore if it isn't there
|
||||||
|
touch /tmp/pactl-default-source
|
||||||
|
echo "$choice" > /tmp/pactl-default-source
|
||||||
|
pactl set-default-source $choice # make sure that the chosen sink is the
|
||||||
13
.local/bin/setvol
Executable file
13
.local/bin/setvol
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
default_loc=/tmp/pactl-default-sink
|
||||||
|
|
||||||
|
if [ ! -f "$default_loc" ] ; then
|
||||||
|
set-default-sink
|
||||||
|
fi
|
||||||
|
|
||||||
|
default=$(cat $default_loc)
|
||||||
|
|
||||||
|
value=$(echo -e "" | dmenu -bw 0 -i -p "Set vol to what?")
|
||||||
|
|
||||||
|
pactl set-sink-volume $default $value%
|
||||||
44
.local/bin/status-bat
Executable file
44
.local/bin/status-bat
Executable file
@ -0,0 +1,44 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
icon=""
|
||||||
|
|
||||||
|
status=$(bash-status-bat)
|
||||||
|
parts=($status)
|
||||||
|
current=$(echo "${parts[0]}" | sed 's/\%//')
|
||||||
|
state=${parts[1]}
|
||||||
|
status="$current%"
|
||||||
|
|
||||||
|
if [[ "$state" == "discharging" ]]; then
|
||||||
|
case $(((current/20)+1)) in
|
||||||
|
1)
|
||||||
|
icon=" "
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
icon=" "
|
||||||
|
;;
|
||||||
|
3)
|
||||||
|
icon=" "
|
||||||
|
;;
|
||||||
|
4)
|
||||||
|
icon=" "
|
||||||
|
;;
|
||||||
|
5)
|
||||||
|
icon=" "
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$state" == "not-charging" ]]; then
|
||||||
|
icon=" "
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$state" == "fully-charged" ]]; then
|
||||||
|
icon=" "
|
||||||
|
status="Full"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$state" == "charging" ]]; then
|
||||||
|
icon=" "
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$icon $status"
|
||||||
10
.local/bin/status-disk
Executable file
10
.local/bin/status-disk
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
freemb=$(df -h -B 1048576 | grep "/$" | awk -F ' ' '{ print $4 }')
|
||||||
|
freegb=$(df -h -B 1048576 | grep "/$" | awk -F ' ' '{ print $4/1024 }')
|
||||||
|
|
||||||
|
if [ $freemb -lt 1024 ]; then
|
||||||
|
printf " %0.2fMb" $freemb
|
||||||
|
else
|
||||||
|
printf " %0.2fGb" $freegb
|
||||||
|
fi
|
||||||
61
.local/bin/status-net
Executable file
61
.local/bin/status-net
Executable file
@ -0,0 +1,61 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
dev_wifi=$(cat "$HOME"/.config/net-cfg/dev_wifi)
|
||||||
|
dev_eth=$(cat "$HOME"/.config/net-cfg/dev_eth)
|
||||||
|
dev_vpn=$(cat "$HOME"/.config/net-cfg/dev_vpn)
|
||||||
|
|
||||||
|
base03=#002b36
|
||||||
|
base02=#073642
|
||||||
|
base01=#586e75
|
||||||
|
base00=#657b83
|
||||||
|
base0=#839496
|
||||||
|
base1=#93a1a1
|
||||||
|
base2=#eee8d5
|
||||||
|
base3=#fdf6e3
|
||||||
|
yellow=#b58900
|
||||||
|
orange=#cb4b16
|
||||||
|
red=#dc322f
|
||||||
|
magenta=#d33682
|
||||||
|
violet=#6c71c4
|
||||||
|
blue=#268bd2
|
||||||
|
cyan=#2aa198
|
||||||
|
green=#859900
|
||||||
|
|
||||||
|
std_color=$magenta
|
||||||
|
wifi_icon=" "
|
||||||
|
|
||||||
|
color=$std_color;
|
||||||
|
|
||||||
|
eth="$(ip -o address | grep -i "$dev_eth *inet ")"
|
||||||
|
if [ -n "$eth" ]
|
||||||
|
then
|
||||||
|
speed="$(cat /sys/class/net/$dev_eth/speed)"
|
||||||
|
case $speed in
|
||||||
|
10) speed="10Base-T" ;;
|
||||||
|
100) speed="100Base-T" ;;
|
||||||
|
1000) speed="Gigabit" ;;
|
||||||
|
*) speed="UNKNOWN $speed" ;;
|
||||||
|
esac
|
||||||
|
eth_status=" $speed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ssid="$(iw dev $dev_wifi link | grep -i SSID)"
|
||||||
|
if [ -n "$ssid" ]
|
||||||
|
then
|
||||||
|
signal="$(awk '/^\s*w/ { print int($3 * 100 / 70) "%" }' /proc/net/wireless)"
|
||||||
|
wifi_status="$wifi_icon ${signal} ${ssid##*SSID: }"
|
||||||
|
fi
|
||||||
|
|
||||||
|
vpn="$(ip -o address | grep -i "$dev_vpn *inet ")"
|
||||||
|
if [ -n "$vpn" ]
|
||||||
|
then
|
||||||
|
vpn_status=""
|
||||||
|
color=$green
|
||||||
|
else
|
||||||
|
vpn_status=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "${vpn_status} $wifi_status$eth_status"
|
||||||
|
|
||||||
|
|
||||||
|
# vim: ft=sh:expandtab:ts=4:shiftwidth=4
|
||||||
27
.local/bin/status-vol
Executable file
27
.local/bin/status-vol
Executable file
@ -0,0 +1,27 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Prints the current volume or if muted.
|
||||||
|
|
||||||
|
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="$(split "$vol" ".")"
|
||||||
|
vol="${vol##0}"
|
||||||
|
|
||||||
|
case 1 in
|
||||||
|
$((vol >= 70)) ) icon="" ;;
|
||||||
|
$((vol >= 30)) ) icon="" ;;
|
||||||
|
$((vol >= 1)) ) icon="" ;;
|
||||||
|
* ) echo && exit ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "$icon $vol%"
|
||||||
7
.local/bin/switchkb
Executable file
7
.local/bin/switchkb
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
##
|
||||||
|
# Switches to the given keyboard (argument) and sets
|
||||||
|
##
|
||||||
|
|
||||||
|
setxkbmap "$1" -option ctrl:nocaps
|
||||||
28
.local/bin/tmux-sessioniser
Executable file
28
.local/bin/tmux-sessioniser
Executable file
@ -0,0 +1,28 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Simple tool that can be run to create a tmux session or
|
||||||
|
# connect to an existing one.
|
||||||
|
|
||||||
|
if [[ $# -eq 1 ]]; then
|
||||||
|
selected=$1
|
||||||
|
else
|
||||||
|
selected=$(find ~/repos ~/.config ~/ ~/work ~/.xmonad ~/nextcloud -mindepth 1 -maxdepth 1 -type d | fzf)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z $selected ]]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
selected_name=$(basename "$selected" | tr . _)
|
||||||
|
tmux_running=$(pgrep tmux)
|
||||||
|
|
||||||
|
if [[ -z $TMUX ]] && [[ -z $tmux_running ]]; then
|
||||||
|
tmux new-session -s "$selected_name" -c "$selected"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! tmux has-session -t="$selected_name" 2> /dev/null; then
|
||||||
|
tmux new-session -ds "$selected_name" -c "$selected"
|
||||||
|
fi
|
||||||
|
|
||||||
|
tmux switch-client -t "$selected_name"
|
||||||
13
.local/bin/tmux-windowiser
Executable file
13
.local/bin/tmux-windowiser
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
branch_name=$(basename $1)
|
||||||
|
session_name=$(tmux display-message -p "#S")
|
||||||
|
clean_name=$(echo $branch_name | tr "./" "__")
|
||||||
|
target="$session_name:$clean_name"
|
||||||
|
|
||||||
|
if ! tmux has-session -t $target 2> /dev/null; then
|
||||||
|
tmux neww -dn $clean_name
|
||||||
|
fi
|
||||||
|
|
||||||
|
shift
|
||||||
|
tmux send-keys -t $target "$*" Enter
|
||||||
15
.local/bin/tmux-worker
Executable file
15
.local/bin/tmux-worker
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
session="system"
|
||||||
|
|
||||||
|
# Check if the session exists, discarding output
|
||||||
|
# We can check $? for the exit status (zero for success, non-zero for failure)
|
||||||
|
tmux has-session -t $session 2>/dev/null
|
||||||
|
|
||||||
|
if [ $? != 0 ]; then
|
||||||
|
# Set up your session
|
||||||
|
tmux new-session -s "$session"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Attach to created session
|
||||||
|
tmux attach-session -t "$session"
|
||||||
11
.local/bin/toggle-sink-mute
Executable file
11
.local/bin/toggle-sink-mute
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
default_loc=/tmp/pactl-default-sink
|
||||||
|
|
||||||
|
if [ ! -f "$default_loc" ] ; then
|
||||||
|
set-default-sink
|
||||||
|
fi
|
||||||
|
|
||||||
|
default=$(cat $default_loc)
|
||||||
|
|
||||||
|
pactl set-sink-mute $default toggle
|
||||||
11
.local/bin/toggle-source-mute
Executable file
11
.local/bin/toggle-source-mute
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
default_loc=/tmp/pactl-default-source
|
||||||
|
|
||||||
|
if [ ! -f "$default_loc" ] ; then
|
||||||
|
set-default-source
|
||||||
|
fi
|
||||||
|
|
||||||
|
default=$(cat $default_loc)
|
||||||
|
|
||||||
|
pactl set-source-mute $default toggle
|
||||||
13
.local/bin/trayer-toggle
Executable file
13
.local/bin/trayer-toggle
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
test_path="/tmp/trayer.exists"
|
||||||
|
|
||||||
|
if [ -f "$test_path" ]; then
|
||||||
|
echo "stopping trayer"
|
||||||
|
killall trayer
|
||||||
|
rm "$test_path"
|
||||||
|
else
|
||||||
|
echo "starting trayer"
|
||||||
|
touch "$test_path"
|
||||||
|
exec "$@"
|
||||||
|
fi
|
||||||
35
.local/bin/urlencode
Executable file
35
.local/bin/urlencode
Executable file
@ -0,0 +1,35 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# yeah, i totally stole this from stack exchange, no shame
|
||||||
|
# - rwxrob
|
||||||
|
|
||||||
|
# and I stole it from rwxrob
|
||||||
|
# - inkletblot
|
||||||
|
|
||||||
|
rawurlencode() {
|
||||||
|
local string="${1}"
|
||||||
|
local strlen=${#string}
|
||||||
|
local encoded=""
|
||||||
|
local pos c o
|
||||||
|
|
||||||
|
for ((pos = 0; pos < strlen; pos++)); do
|
||||||
|
c=${string:$pos:1}
|
||||||
|
case "$c" in
|
||||||
|
[-_.~a-zA-Z0-9]) o="${c}" ;;
|
||||||
|
*) printf -v o '%%%02x' "'$c'" ;;
|
||||||
|
esac
|
||||||
|
encoded+="${o}"
|
||||||
|
done
|
||||||
|
echo "${encoded}" # You can either set a return variable (FASTER)
|
||||||
|
REPLY="${encoded}" #+or echo the result (EASIER)... or both... :p
|
||||||
|
}
|
||||||
|
|
||||||
|
if test -n "$1"; then
|
||||||
|
rawurlencode "$*"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
IFS=
|
||||||
|
while read -r line; do
|
||||||
|
rawurlencode "$line"
|
||||||
|
done
|
||||||
4
.local/bin/vic
Executable file
4
.local/bin/vic
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
cmd=$(command -v $1)
|
||||||
|
test -n "$cmd" && exec vi "$cmd"
|
||||||
9
.local/bin/xmobar-status-bat
Executable file
9
.local/bin/xmobar-status-bat
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# a simple wrapper for inserting xmobar stuff
|
||||||
|
|
||||||
|
status=$(status-bat)
|
||||||
|
|
||||||
|
parts=($status)
|
||||||
|
|
||||||
|
echo "<fn=1>${parts[0]} </fn> ${parts[1]}"
|
||||||
7
.local/bin/xmobar-status-disk
Executable file
7
.local/bin/xmobar-status-disk
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
status=$(status-disk)
|
||||||
|
|
||||||
|
parts=($status)
|
||||||
|
|
||||||
|
echo "<fn=1>${parts[0]} </fn> ${parts[1]}"
|
||||||
32
.local/bin/xmobar-status-keyboard
Executable file
32
.local/bin/xmobar-status-keyboard
Executable file
@ -0,0 +1,32 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
stdlayout=us # standard layout takes "default" color
|
||||||
|
stdname=en-us # arbitrary, descriptive only
|
||||||
|
|
||||||
|
base03=#002b36
|
||||||
|
base02=#073642
|
||||||
|
base01=#586e75
|
||||||
|
base00=#657b83
|
||||||
|
base0=#839496
|
||||||
|
base1=#93a1a1
|
||||||
|
base2=#eee8d5
|
||||||
|
base3=#fdf6e3
|
||||||
|
yellow=#b58900
|
||||||
|
orange=#cb4b16
|
||||||
|
red=#dc322f
|
||||||
|
magenta=#d33682
|
||||||
|
violet=#6c71c4
|
||||||
|
blue=#268bd2
|
||||||
|
cyan=#2aa198
|
||||||
|
green=#859900
|
||||||
|
|
||||||
|
layout="$(xkb-switch)"
|
||||||
|
|
||||||
|
case $layout in
|
||||||
|
${stdlayout}) color=$green; icon=" "; name=$stdname ;; # f11c fa-keyboard-o
|
||||||
|
*) color=$magenta; icon=""; name="dvorak" ;; # f11c fa-keyboard-o
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "<fc=$color><fn=1>$icon </fn> ${name}</fc>"
|
||||||
|
|
||||||
|
# vim: ft=sh:expandtab:ts=4:shiftwidth=4
|
||||||
87
.local/bin/xmobar-status-net
Executable file
87
.local/bin/xmobar-status-net
Executable file
@ -0,0 +1,87 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
dev_wifi=$(cat "$HOME"/.config/xmobar/dev_wifi)
|
||||||
|
dev_eth=$(cat "$HOME"/.config/xmobar/dev_eth)
|
||||||
|
dev_vpn=$(cat "$HOME"/.config/xmobar/dev_vpn)
|
||||||
|
|
||||||
|
# base03=#002b36
|
||||||
|
# base02=#073642
|
||||||
|
# base01=#586e75
|
||||||
|
# base00=#657b83
|
||||||
|
# base0=#839496
|
||||||
|
# base1=#93a1a1
|
||||||
|
# base2=#eee8d5
|
||||||
|
# base3=#fdf6e3
|
||||||
|
yellow=#b58900
|
||||||
|
# orange=#cb4b16
|
||||||
|
red=#dc322f
|
||||||
|
magenta=#d33682
|
||||||
|
# violet=#6c71c4
|
||||||
|
# blue=#268bd2
|
||||||
|
# cyan=#2aa198
|
||||||
|
green=#859900
|
||||||
|
|
||||||
|
# connectivity status
|
||||||
|
# states are:
|
||||||
|
# none (no connectivity)
|
||||||
|
# portal (behind captive portal)
|
||||||
|
# limited (connected to network but no internet access)
|
||||||
|
# full (full internet connectivity)
|
||||||
|
# unknown
|
||||||
|
|
||||||
|
std_color=$magenta
|
||||||
|
wifi_icon=""
|
||||||
|
|
||||||
|
connectivity="$(nmcli networking connectivity)"
|
||||||
|
|
||||||
|
case $connectivity in
|
||||||
|
none) color=$red; icon="" ;; # f056 fa-minus-circle
|
||||||
|
portal) color=$yellow; icon="" ;; # f05c fa-times-circle-o
|
||||||
|
limited) color=$yellow; icon="" ;; # f01b fa-arrow-circle-o-up
|
||||||
|
full) color=$std_color; icon="" ;; # f0aa fa-arrow-circle-up
|
||||||
|
*) color=$red; icon="" ;; # f29c fa-question-circle-o
|
||||||
|
esac
|
||||||
|
|
||||||
|
eth="$(ip -o address | grep -i "$dev_eth *inet ")"
|
||||||
|
if [ -n "$eth" ]
|
||||||
|
then
|
||||||
|
#eth="${eth##*inet }"
|
||||||
|
speed="$(cat /sys/class/net/"$dev_eth"/speed)"
|
||||||
|
case $speed in
|
||||||
|
10) speed="10Base-T" ;;
|
||||||
|
100) speed="100Base-T" ;;
|
||||||
|
1000) speed="Gigabit" ;;
|
||||||
|
*) speed="UNKNOWN $speed" ;;
|
||||||
|
esac
|
||||||
|
#eth_status=" <fn=1></fn> $speed ${eth%%/*}"
|
||||||
|
eth_status=" <fn=1> </fn> $speed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ssid="$(iw dev "$dev_wifi" link | grep -i SSID)"
|
||||||
|
if [ -n "$ssid" ]
|
||||||
|
then
|
||||||
|
signal="$(iw dev "$dev_wifi" station dump | grep -E '[^ ]signal avg')"
|
||||||
|
signal="${signal#*-}"
|
||||||
|
signal="${signal%% *}"
|
||||||
|
signal="$((2*(100-signal)))"
|
||||||
|
|
||||||
|
signal=$((signal/5*5)) # get rid of some jitter
|
||||||
|
((signal > 100)) && signal=100
|
||||||
|
wifi_status=" <fn=1>$wifi_icon </fn> <fc=$green>${signal}</fc>% ${ssid##*SSID: }"
|
||||||
|
fi
|
||||||
|
|
||||||
|
vpn="$(ip -o address | grep -i "$dev_vpn *inet ")"
|
||||||
|
if [ -n "$vpn" ]
|
||||||
|
then
|
||||||
|
#vpn="${vpn##*inet }"
|
||||||
|
#vpn_status="<fn=1></fn> ${vpn%%/*}"
|
||||||
|
vpn_status="<fn=1> </fn> "
|
||||||
|
color=$green
|
||||||
|
else
|
||||||
|
vpn_status="<fn=1> </fn> "
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "<fc=$color>${vpn_status}<fn=1>$icon </fn>${connectivity##*full}$wifi_status$eth_status</fc>"
|
||||||
|
|
||||||
|
|
||||||
|
# vim: ft=sh:expandtab:ts=4:shiftwidth=4
|
||||||
6
.local/bin/xmobar-status-updates
Executable file
6
.local/bin/xmobar-status-updates
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
count=$(yay -Qu | wc -l)
|
||||||
|
icon=""
|
||||||
|
|
||||||
|
echo "<fn=1>$icon </fn> $count"
|
||||||
46
.local/bin/xmobar-status-vol
Executable file
46
.local/bin/xmobar-status-vol
Executable file
@ -0,0 +1,46 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
base03=#002b36
|
||||||
|
base02=#073642
|
||||||
|
base01=#586e75
|
||||||
|
base00=#657b83
|
||||||
|
base0=#839496
|
||||||
|
base1=#93a1a1
|
||||||
|
base2=#eee8d5
|
||||||
|
base3=#fdf6e3
|
||||||
|
yellow=#b58900
|
||||||
|
orange=#cb4b16
|
||||||
|
red=#dc322f
|
||||||
|
magenta=#d33682
|
||||||
|
violet=#6c71c4
|
||||||
|
blue=#268bd2
|
||||||
|
cyan=#2aa198
|
||||||
|
green=#859900
|
||||||
|
|
||||||
|
color=$cyan
|
||||||
|
vol="$(pamixer --get-volume)"
|
||||||
|
|
||||||
|
if [ $(pamixer --get-mute) = true ]; then
|
||||||
|
vol=MUTE
|
||||||
|
color=$red
|
||||||
|
icon="" # fa-volume-off f026
|
||||||
|
|
||||||
|
echo "<fc=$color><fn=1>$icon </fn>$vol</fc>"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$vol" -gt "100" ]; then
|
||||||
|
icon=""
|
||||||
|
color=$orange
|
||||||
|
elif [ "$vol" -gt "70" ]; then
|
||||||
|
icon=""
|
||||||
|
elif [ "$vol" -gt "30" ]; then
|
||||||
|
icon=""
|
||||||
|
elif [ "$vol" -gt "0" ]; then
|
||||||
|
icon=""
|
||||||
|
else
|
||||||
|
vol=MUTE
|
||||||
|
color=$red
|
||||||
|
icon=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "<fc=$color><fn=1>$icon </fn>$vol</fc>"
|
||||||
36
.local/bin/xmobar-status-weather
Executable file
36
.local/bin/xmobar-status-weather
Executable file
@ -0,0 +1,36 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# simple script to read weather from airport code and return it for display in xmobar
|
||||||
|
|
||||||
|
weather=$(weather-report $1 -m --no-cache -n | \
|
||||||
|
grep -e '\[' \
|
||||||
|
-e 'Temp' | \
|
||||||
|
sed -e 's/\[using result //' \
|
||||||
|
-e 's/,.*\]//' \
|
||||||
|
-e 's/Temp.*: //' \
|
||||||
|
-e 's/ C//' \
|
||||||
|
-e 's/ //')
|
||||||
|
|
||||||
|
readarray -t y <<< "$weather"
|
||||||
|
|
||||||
|
loc=${y[0]}
|
||||||
|
temp=${y[1]}
|
||||||
|
color=""
|
||||||
|
|
||||||
|
if ((temp > 30))
|
||||||
|
then
|
||||||
|
color="#ff5555"
|
||||||
|
elif ((temp > 25))
|
||||||
|
then
|
||||||
|
color="#ffb86c"
|
||||||
|
elif ((temp > 20))
|
||||||
|
then
|
||||||
|
color="#f1fa8c"
|
||||||
|
elif ((temp > 10))
|
||||||
|
then
|
||||||
|
color="#50fa7b"
|
||||||
|
else
|
||||||
|
color="#8be9fd"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "<fc=#ff79c6>$loc <fc=$color>$temp</fc>C</fc>"
|
||||||
48
.local/bin/xmobar-trayer-padding-icon
Executable file
48
.local/bin/xmobar-trayer-padding-icon
Executable file
@ -0,0 +1,48 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Copied from https://github.com/jaor/xmobar/issues/239#issuecomment-233206552
|
||||||
|
# Detects the width of running trayer-srg window (xprop name 'panel')
|
||||||
|
# and creates an XPM icon of that width, 1px height, and transparent.
|
||||||
|
# Outputs an <icon>-tag for use in xmobar to display the generated
|
||||||
|
# XPM icon.
|
||||||
|
#
|
||||||
|
# Run script from xmobar:
|
||||||
|
# `Run Com "/where/ever/trayer-padding-icon.sh" [] "trayerpad" 10`
|
||||||
|
# and use `%trayerpad%` in your template.
|
||||||
|
|
||||||
|
|
||||||
|
# Function to create a transparent Wx1 px XPM icon
|
||||||
|
create_xpm_icon () {
|
||||||
|
timestamp=$(date)
|
||||||
|
pixels=$(for i in `seq $1`; do echo -n "."; done)
|
||||||
|
|
||||||
|
cat << EOF > "$2"
|
||||||
|
/* XPM *
|
||||||
|
static char * trayer_pad_xpm[] = {
|
||||||
|
/* This XPM icon is used for padding in xmobar to */
|
||||||
|
/* leave room for trayer-srg. It is dynamically */
|
||||||
|
/* updated by by trayer-padding-icon.sh which is run */
|
||||||
|
/* by xmobar. */
|
||||||
|
/* Created: ${timestamp} */
|
||||||
|
/* <w/cols> <h/rows> <colors> <chars per pixel> */
|
||||||
|
"$1 1 1 1",
|
||||||
|
/* Colors (none: transparent) */
|
||||||
|
". c none",
|
||||||
|
/* Pixels */
|
||||||
|
"$pixels"
|
||||||
|
};
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
# Width of the trayer window
|
||||||
|
width=$(xprop -name panel | grep 'program specified minimum size' | cut -d ' ' -f 5)
|
||||||
|
|
||||||
|
# Icon file name
|
||||||
|
iconfile="/tmp/trayer-padding-${width}px.xpm"
|
||||||
|
|
||||||
|
# If the desired icon does not exist create it
|
||||||
|
if [ ! -f $iconfile ]; then
|
||||||
|
create_xpm_icon $width $iconfile
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Output the icon tag for xmobar
|
||||||
|
echo "<icon=${iconfile}/>"
|
||||||
12
.local/bin/xmonad-keys-help
Executable file
12
.local/bin/xmonad-keys-help
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
sed -n '/--START_KEYS/,/--END_KEYS/p' $HOME/.xmonad/xmonad.hs | \
|
||||||
|
grep -e ', ("' \
|
||||||
|
-e '\[ ("' \
|
||||||
|
-e '--NOTE' | \
|
||||||
|
grep -v '\-\- , ' |\
|
||||||
|
sed -e 's/^[ \t,]*//' \
|
||||||
|
-e 's/\[ (/(/' \
|
||||||
|
-e 's/--NOTE /\n/' \
|
||||||
|
-e 's/, / --> /' | \
|
||||||
|
yad --text-info --back=#121e32 --fore=#dfdfef --geometry=1200x800
|
||||||
40
.local/bin/zk-gen-dir-md-toc
Executable file
40
.local/bin/zk-gen-dir-md-toc
Executable file
@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Generates a simple index of the current folder and subfolders creating
|
||||||
|
# a table of contents of all of the .md files contained within.
|
||||||
|
|
||||||
|
long_contents=$(find . | sort)
|
||||||
|
|
||||||
|
# replace the absolute path in all lines
|
||||||
|
contents=${long_contents//\.\//}
|
||||||
|
|
||||||
|
prev=""
|
||||||
|
|
||||||
|
echo "$contents" | while read -r line || [[ -n $line ]];
|
||||||
|
do
|
||||||
|
# the line contains a file, or hidden dir
|
||||||
|
if [[ $line == *"."* ]]; then
|
||||||
|
# if the line is an md, not in the .zk dir, and not a dir
|
||||||
|
if [[ $line == *".md"* && ! -d "$line" && $line != *".zk"* ]]; then
|
||||||
|
# extract the name of the file
|
||||||
|
name=$(echo "$line" | sed 's/.*\///' | sed 's/\.md//')
|
||||||
|
# create the link
|
||||||
|
name="[$name]($line)"
|
||||||
|
else
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# the folders are titles
|
||||||
|
name=$(echo -e "\n## $line")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# two titles in a row means empty folder.
|
||||||
|
if [[ $prev == *"##"* && $name == *"##"* ]]; then
|
||||||
|
prev=$name
|
||||||
|
name=$(echo -e "Folder Empty.\n$prev")
|
||||||
|
else
|
||||||
|
prev=$name
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$name"
|
||||||
|
done
|
||||||
14
.local/bin/zk-gen-index
Executable file
14
.local/bin/zk-gen-index
Executable file
@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
toc=$(zk-gen-dir-md-toc)
|
||||||
|
|
||||||
|
echo -e "START_TOC$toc\nEND_TOC" > temp.md
|
||||||
|
|
||||||
|
if [ -f index.md ]; then
|
||||||
|
perl -i -p0e 's/START_TOC.*END_TOC/`cat temp.md`/se' index.md
|
||||||
|
# sed -i "s/START_TOC.*END_TOC/\${toc}/g" index.md
|
||||||
|
else
|
||||||
|
echo -e "# Index\n\nSTART_TOC\n$toc\nEND_TOC" > index.md
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm temp.md
|
||||||
3
scripts/ganttproject
Executable file
3
scripts/ganttproject
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
/opt/ganttproject/ganttproject
|
||||||
33
scripts/update-dmenu-bluetooth
Executable file
33
scripts/update-dmenu-bluetooth
Executable file
@ -0,0 +1,33 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo "This script will clone Layerex's dmenu-bluetooth and copy the scripts from it that I use."
|
||||||
|
read -r -p "Are you sure you want to continue [Y/n]" input
|
||||||
|
|
||||||
|
case $input in
|
||||||
|
[nN][oO] | [nN])
|
||||||
|
echo "Okay, exiting..."
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf "\n"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
git clone https://github.com/Layerex/dmenu-bluetooth
|
||||||
|
|
||||||
|
printf "\nCopying scripts...\n"
|
||||||
|
|
||||||
|
dir="dmenu-bluetooth"
|
||||||
|
|
||||||
|
if [ -d "$dir" ]; then
|
||||||
|
for script in "$HOME"/.local/bin/*; do
|
||||||
|
if [ -f "./$dir/${script##*/}" ]; then
|
||||||
|
cp "./$dir/${script##*/}" "$HOME/.local/bin/" -v
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
printf "\nRemoving %s..." "$dir"
|
||||||
|
rm -rf "./$dir" && printf "\nUpdate Complete."
|
||||||
|
else
|
||||||
|
echo "directory $dir does not exist"
|
||||||
|
fi
|
||||||
33
scripts/update-networkmanager-dmenu
Executable file
33
scripts/update-networkmanager-dmenu
Executable file
@ -0,0 +1,33 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "This script will clone firecat53's networkmanager-dmenu and copy the scripts from it that I use."
|
||||||
|
read -r -p "Are you sure you want to continue [Y/n]" input
|
||||||
|
|
||||||
|
case $input in
|
||||||
|
[nN][oO] | [nN])
|
||||||
|
echo "Okay, exiting..."
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf "\n"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
git clone https://github.com/firecat53/networkmanager-dmenu
|
||||||
|
|
||||||
|
printf "\nCopying scripts...\n"
|
||||||
|
|
||||||
|
dir="networkmanager-dmenu"
|
||||||
|
|
||||||
|
if [ -d "$dir" ]; then
|
||||||
|
for script in "$HOME"/.local/bin/*; do
|
||||||
|
if [ -f "./$dir/${script##*/}" ]; then
|
||||||
|
cp "./$dir/${script##*/}" "$HOME/.local/bin/" -v
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
printf "\nRemoving %s..." "$dir"
|
||||||
|
rm -rf "./$dir" && printf "\nUpdate Complete."
|
||||||
|
else
|
||||||
|
echo "directory $dir does not exist"
|
||||||
|
fi
|
||||||
40
scripts/update-voidrice
Executable file
40
scripts/update-voidrice
Executable file
@ -0,0 +1,40 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# I use some of Luke Smiths scripts and although they don't often update, they are known to.
|
||||||
|
# The output is going to include a bunch of copy errors as I'm just copying each file in this directory from his .local/bin back to here, obviously my custom scripts won't exist so they'll fail.
|
||||||
|
|
||||||
|
echo "This script will clone Luke Smith's voidrice and copy the scripts from it that I use."
|
||||||
|
read -r -p "Are you sure you want to continue [Y/n]" input
|
||||||
|
|
||||||
|
case $input in
|
||||||
|
[nN][oO] | [nN])
|
||||||
|
echo "Okay, exiting..."
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf "\n"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
git clone https://github.com/LukeSmithxyz/voidrice
|
||||||
|
|
||||||
|
printf "\nCopying scripts...\n"
|
||||||
|
|
||||||
|
if [ -d voidrice ]; then
|
||||||
|
for script in "$HOME"/.local/bin/*; do
|
||||||
|
if [ -f "./voidrice/.local/bin/${script##*/}" ]; then
|
||||||
|
cp "./voidrice/.local/bin/${script##*/}" "$HOME/.local/bin/" -v
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
for cron in "$HOME"/.local/bin/cron/*; do
|
||||||
|
if [ -f "./voidrice/.local/bin/cron/${cron##*/}" ]; then
|
||||||
|
cp "./voidrice/.local/bin/cron/${cron##*/}" "$HOME/.local/bin/cron/" -v
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
printf "\nRemoving voidrice..."
|
||||||
|
rm -rf ./voidrice && printf "\nUpdate Complete."
|
||||||
|
else
|
||||||
|
echo "directory voidrice does not exist"
|
||||||
|
fi
|
||||||
3
scripts/zotero
Executable file
3
scripts/zotero
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
/opt/zotero/zotero
|
||||||
Loading…
Reference in New Issue
Block a user