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
|
||||
|
||||
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.
|
||||
# See bash(1) for more options
|
||||
|
||||
@ -178,6 +178,8 @@ map gcxm cd ~/.xmonad
|
||||
map gcs cd ~/.config/shell
|
||||
map gcz cd ~/.config/zsh
|
||||
map gcx1 cd ~/.config/x11
|
||||
map gll cd ~/.local
|
||||
map glb cd ~/.local/bin
|
||||
map gw cd ~/work
|
||||
map gNN cd ~/notes/
|
||||
map gNw cd ~/notes/zk/work/
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# If you come from bash you might have to change your $PATH.
|
||||
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.
|
||||
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