mirror of
https://github.com/ItsDrike/dotfiles.git
synced 2025-06-29 04:00:42 +00:00
Initial commit
This commit is contained in:
parent
b912871070
commit
a3e01caebf
157 changed files with 9696 additions and 0 deletions
153
home/.local/bin/scripts/gui/brightness
Executable file
153
home/.local/bin/scripts/gui/brightness
Executable file
|
@ -0,0 +1,153 @@
|
|||
#!/bin/sh
|
||||
|
||||
|
||||
# Parse arguments
|
||||
# ------------------------------------------------------------------------------------
|
||||
BRIGHTNESS_DIR="/sys/class/backlight/*"
|
||||
SEND_NOTIFICATION=0
|
||||
URGENCY="normal"
|
||||
INCREASE=0
|
||||
DECREASE=0
|
||||
SET=0
|
||||
BRIGHTNESS=0
|
||||
|
||||
while [ "$1" ]; do
|
||||
case "$1" in
|
||||
-h | --help)
|
||||
cat << EOF
|
||||
brightness is a cli tool that for displaying or modifying screen brightness.
|
||||
|
||||
Options:
|
||||
-h | --help: Display this message
|
||||
-n | --notification: Produce a desktop notification with brightness info
|
||||
-N | --no-notification: Don't produce a desktop notification with brightness info
|
||||
-u | --urgency [URGENCY]: Pass over notify-send urgency attribute (default: normal)
|
||||
-i | --increase [BRIGHTNESS]: Increase the brightness by given amount
|
||||
-d | --decrease [BRIGHTNESS]: Decrease the brightness by given amount
|
||||
-s | --set [BRIGHTNESS]: Set new brightness level
|
||||
-p | --path [DIR_PATH]: Path to brightness directory (default: /sys/class/backlight/*)
|
||||
|
||||
Valid values:
|
||||
URGENCY: low, normal, critical
|
||||
DIR_PATH: Valid path to a directory
|
||||
BRIGHTNESS:
|
||||
specific value - Example: 10
|
||||
percentage value - Example: 10%
|
||||
EOF
|
||||
exit 0
|
||||
;;
|
||||
-n | --notification)
|
||||
SEND_NOTIFICATION=1
|
||||
;;
|
||||
-N | --no-notification)
|
||||
SEND_NOTIFICATION=0
|
||||
;;
|
||||
-u | --urgency)
|
||||
URGENCY="$2"
|
||||
shift
|
||||
;;
|
||||
-i | --increase)
|
||||
INCREASE=1
|
||||
BRIGHTNESS="$2"
|
||||
shift
|
||||
;;
|
||||
-d | --decrease)
|
||||
DECREASE=1
|
||||
BRIGHTNESS="$2"
|
||||
shift
|
||||
;;
|
||||
-s | --set)
|
||||
SET=1
|
||||
BRIGHTNESS="$2"
|
||||
shift
|
||||
;;
|
||||
-p | --path)
|
||||
BRIGHTNESS_DIR="$2"
|
||||
shift
|
||||
;;
|
||||
* )
|
||||
echo "Unknown argument '$1', use -h or --help for help"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# Define constants based on parsed arguments
|
||||
# ------------------------------------------------------------------------------------
|
||||
BRIGHTNESS_FILE="$BRIGHTNESS_DIR/brightness"
|
||||
BRIGHTNESS_MAX="$(cat $BRIGHTNESS_DIR/max_brightness)"
|
||||
|
||||
|
||||
# Helper functins
|
||||
# ------------------------------------------------------------------------------------
|
||||
|
||||
# Send brightness level desktop notification, showing the given brightness level
|
||||
# as progress bar, along with given message.
|
||||
# $1 - brightness level (number 0-100)
|
||||
# $2 - message (notification body)
|
||||
send_brightness_notify() {
|
||||
percent_brightness="$1"
|
||||
msg="$2"
|
||||
|
||||
notify-send \
|
||||
--app-name=brightness \
|
||||
--urgency="$URGENCY" \
|
||||
-h int:value:$percent_brightness \
|
||||
-h string:synchronous:brightness \
|
||||
"brightness" "$msg"
|
||||
}
|
||||
|
||||
|
||||
# Set brightness to given absolute value
|
||||
# $1 - brightness absolute value
|
||||
set_brightness() {
|
||||
# there should be sudo config allowing this command without password
|
||||
echo "$1" | sudo tee $BRIGHTNESS_FILE >/dev/null
|
||||
}
|
||||
|
||||
|
||||
# Main Logic
|
||||
# ------------------------------------------------------------------------------------
|
||||
|
||||
# Determine the absolute new brightness level
|
||||
if [ $INCREASE -eq 1 ] || [ $DECREASE -eq 1 ] || [ $SET -eq 1 ]; then
|
||||
# If we're dealing with percentages, change to absolutes
|
||||
if echo "$BRIGHTNESS" | grep -qE '%$'; then
|
||||
numeric=$(echo "$BRIGHTNESS" | sed 's/.$//')
|
||||
absolute=$(echo "($BRIGHTNESS_MAX / 100) * $numeric" | bc -l)
|
||||
BRIGHTNESS=$(printf "%.0f" $absolute)
|
||||
fi
|
||||
|
||||
# Get the new requested absolute brightness
|
||||
if [ $SET -eq 1 ]; then
|
||||
new_brightness=$BRIGHTNESS
|
||||
elif [ $DECREASE -eq 1 ]; then
|
||||
cur_brightness=$(cat $BRIGHTNESS_FILE)
|
||||
new_brightness=$(($cur_brightness - $BRIGHTNESS))
|
||||
else
|
||||
cur_brightness=$(cat $BRIGHTNESS_FILE)
|
||||
new_brightness=$(($cur_brightness + $BRIGHTNESS))
|
||||
fi
|
||||
|
||||
# Ensure we respect max/min boundaries
|
||||
if [ $new_brightness -lt 0 ]; then
|
||||
new_brightness=0
|
||||
elif [ $new_brightness -gt $BRIGHTNESS_MAX ]; then
|
||||
new_brightness=$BRIGHTNESS_MAX
|
||||
fi
|
||||
|
||||
# Update the brightness
|
||||
set_brightness $new_brightness
|
||||
fi
|
||||
|
||||
cur_brightness=$(cat $BRIGHTNESS_FILE)
|
||||
percent_brightness=$(echo "($cur_brightness / $BRIGHTNESS_MAX) * 100" | bc -l)
|
||||
percent_brightness_2f=$(printf "%.2f" $percent_brightness)
|
||||
percent_brightness_rounded=$(printf "%.0f" $percent_brightness)
|
||||
|
||||
if [ $SEND_NOTIFICATION -eq 1 ]; then
|
||||
send_brightness_notify "$percent_brightness_rounded" "Level: $percent_brightness_rounded"
|
||||
fi
|
||||
|
||||
echo "Brightness: ${percent_brightness_2f}% (absolute: $cur_brightness)"
|
11
home/.local/bin/scripts/gui/deskopen
Executable file
11
home/.local/bin/scripts/gui/deskopen
Executable file
|
@ -0,0 +1,11 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Find the line with exec, if there's multiple lines
|
||||
# use the last one
|
||||
exec_line=$(grep '^Exec' "$1" | tail -1)
|
||||
# Remove 'Exec' and arguments (%u, %f, ...)
|
||||
cmd=$(echo $exec_line | sed 's/^Exec=//' | sed 's/%.//')
|
||||
# Remove "" around command (if present)
|
||||
cmd=$(echo $cmd | sed 's/^"//g' | sed 's/" *$//g')
|
||||
# Run the exec line of the application using /bin/sh
|
||||
/bin/sh -c "$cmd"
|
9
home/.local/bin/scripts/gui/dmenu
Executable file
9
home/.local/bin/scripts/gui/dmenu
Executable file
|
@ -0,0 +1,9 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Compatibility executable script for applications running dmenu, which
|
||||
# runs wofi in dmenu mode instead. Note: In many cases the arguments won't
|
||||
# be compatible and this will fail, however the primary way scripts use
|
||||
# dmenu is just for simple prompts, using the `-p` flag. and wofi does fully
|
||||
# support this usage.
|
||||
|
||||
cat | wofi --dmenu $@
|
85
home/.local/bin/scripts/gui/dmenu-scripts/displayselect
Executable file
85
home/.local/bin/scripts/gui/dmenu-scripts/displayselect
Executable file
|
@ -0,0 +1,85 @@
|
|||
|
||||
#!/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.
|
||||
command -v setbg >/dev/null && setbg # Fix background if screen size/arangement has changed.
|
||||
}
|
||||
|
||||
# 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
|
||||
if [ "$(echo "$screens" | wc -l)" -lt 2 ]; then
|
||||
onescreen "$screens"
|
||||
notify-send "💻 Only one screen detected." "Using it in its optimal settings..."
|
||||
else
|
||||
# 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
|
||||
fi
|
||||
|
||||
|
||||
postrun
|
11
home/.local/bin/scripts/gui/dmenu-scripts/dman
Executable file
11
home/.local/bin/scripts/gui/dmenu-scripts/dman
Executable file
|
@ -0,0 +1,11 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Dmenu prompt to easily search for a man page to open
|
||||
|
||||
page="$(apropos --long "$1" | dmenu -i -l 10 | awk '{print $2, $1}' | tr -d '()')"
|
||||
|
||||
if tty -s; then
|
||||
man $page
|
||||
else
|
||||
$TERMINAL -e man $page
|
||||
fi
|
68
home/.local/bin/scripts/gui/dmenu-scripts/dmenumount
Executable file
68
home/.local/bin/scripts/gui/dmenu-scripts/dmenumount
Executable file
|
@ -0,0 +1,68 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Gives 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
|
||||
# existing 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."
|
||||
}
|
||||
|
||||
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"
|
||||
simple-mtpfs --device "$chosen" "$mp"
|
||||
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."
|
||||
}
|
||||
|
||||
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,mountpoint" | grep 'part\|rom' | awk '$4==""{printf "%s (%s)\n",$1,$3}')"
|
||||
|
||||
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
|
6
home/.local/bin/scripts/gui/dmenu-scripts/dmenupass
Executable file
6
home/.local/bin/scripts/gui/dmenu-scripts/dmenupass
Executable file
|
@ -0,0 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
# This script is the value for SUDO_ASKPASS variable,
|
||||
# meaning that it will be used as a password prompt if needed.
|
||||
|
||||
dmenu -P -p "$1"
|
22
home/.local/bin/scripts/gui/dmenu-scripts/dmenuprompt
Executable file
22
home/.local/bin/scripts/gui/dmenu-scripts/dmenuprompt
Executable file
|
@ -0,0 +1,22 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Opens a basic yes/no prompt with dmenu
|
||||
# This is useful for confirming whether an action should be taken
|
||||
|
||||
# First try to run with restrict (-r) flag
|
||||
# however not everyone has this patch applied, so if that fails, fall back
|
||||
out="$(printf "No\nYes" | dmenu -i -r -p "$1" 2>/dev/null)"
|
||||
if [ $? -ne 0 ]; then
|
||||
out="$(printf "No\nYes" | dmenu -i -p "$1")"
|
||||
fi
|
||||
|
||||
|
||||
if [ "$out" == "Yes" ]; then
|
||||
exit 0
|
||||
elif [ "$out" == "No" ]; then
|
||||
exit 1
|
||||
else
|
||||
# Dmenu allows invalid picks by explicitly typing in a different option
|
||||
# when that happens, end with code 2 instead.
|
||||
exit 2
|
||||
fi
|
121
home/.local/bin/scripts/gui/dmenu-scripts/dmenurecord
Executable file
121
home/.local/bin/scripts/gui/dmenu-scripts/dmenurecord
Executable file
|
@ -0,0 +1,121 @@
|
|||
|
||||
#!/bin/sh
|
||||
|
||||
# Usage:
|
||||
# `$0`: Ask for recording type via dmenu
|
||||
# `$0 screencast`: Record both audio and screen
|
||||
# `$0 video`: Record only screen
|
||||
# `$0 audio`: Record only audio
|
||||
# `$0 kill`: Kill existing recording
|
||||
#
|
||||
# If there is already a running instance, user will be prompted to end it.
|
||||
|
||||
screencast() {
|
||||
ffmpeg -y \
|
||||
-f x11grab \
|
||||
-framerate 60 \
|
||||
-s "$(xdpyinfo | grep dimensions | awk '{print $2;}')" \
|
||||
-i "$DISPLAY" \
|
||||
-f alsa -i default \
|
||||
-r 30 \
|
||||
-c:v h264 -crf 0 -preset ultrafast -c:a aac \
|
||||
"$HOME/screencast-$(date '+%y%m%d-%H%M-%S').mp4" &
|
||||
echo $! > /tmp/recordingpid
|
||||
}
|
||||
|
||||
video() {
|
||||
ffmpeg \
|
||||
-f x11grab \
|
||||
-s "$(xdpyinfo | grep dimensions | awk '{print $2;}')" \
|
||||
-i "$DISPLAY" \
|
||||
-c:v libx264 -qp 0 -r 30 \
|
||||
"$HOME/video-$(date '+%y%m%d-%H%M-%S').mkv" &
|
||||
echo $! > /tmp/recordingpid
|
||||
}
|
||||
|
||||
webcamhidef() {
|
||||
ffmpeg \
|
||||
-f v4l2 \
|
||||
-i /dev/video0 \
|
||||
-video_size 1920x1080 \
|
||||
"$HOME/webcam-$(date '+%y%m%d-%H%M-%S').mkv" &
|
||||
echo $! > /tmp/recordingpid
|
||||
}
|
||||
|
||||
webcam() {
|
||||
ffmpeg \
|
||||
-f v4l2 \
|
||||
-i /dev/video0 \
|
||||
-video_size 640x480 \
|
||||
"$HOME/webcam-$(date '+%y%m%d-%H%M-%S').mkv" &
|
||||
echo $! > /tmp/recordingpid
|
||||
}
|
||||
|
||||
|
||||
audio() {
|
||||
ffmpeg \
|
||||
-f alsa -i default \
|
||||
"$HOME/audio-$(date '+%y%m%d-%H%M-%S').mp3" &
|
||||
echo $! > /tmp/recordingpid
|
||||
}
|
||||
|
||||
asktoend() {
|
||||
response=$(printf "No\\nYes" | dmenu -i -p "Recording still active. End recording?") &&
|
||||
[ "$response" = "Yes" ] && killrecording
|
||||
}
|
||||
|
||||
videoselected()
|
||||
{
|
||||
slop -f "%x %y %w %h" > /tmp/slop
|
||||
read -r X Y W H < /tmp/slop
|
||||
rm /tmp/slop
|
||||
|
||||
ffmpeg \
|
||||
-f x11grab \
|
||||
-framerate 60 \
|
||||
-video_size "$W"x"$H" \
|
||||
-i :0.0+"$X,$Y" \
|
||||
-c:v libx264 -qp 0 -r 30 \
|
||||
"$HOME/box-$(date '+%y%m%d-%H%M-%S').mkv" &
|
||||
echo $! > /tmp/recordingpid
|
||||
}
|
||||
|
||||
killrecording() {
|
||||
recpid="$(cat /tmp/recordingpid)"
|
||||
# kill with SIGTERM, allowing finishing touches.
|
||||
kill -15 "$recpid" 2>/dev/null
|
||||
rm -f /tmp/recordingpid
|
||||
# even after SIGTERM, ffmpeg may still run, so SIGKILL it.
|
||||
sleep 3
|
||||
kill -9 "$recpid" 2>/dev/null
|
||||
exit
|
||||
}
|
||||
|
||||
askrecording() { \
|
||||
choice=$(printf "screencast\\nvideo\\nvideo selected\\naudio\\nwebcam\\nwebcam (hi-def)" | dmenu -i -p "Select recording style:")
|
||||
case "$choice" in
|
||||
screencast) screencast;;
|
||||
audio) audio;;
|
||||
video) video;;
|
||||
*selected) videoselected;;
|
||||
webcam) webcam;;
|
||||
"webcam (hi-def)") webcamhidef;;
|
||||
esac
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
screencast) screencast;;
|
||||
audio) audio;;
|
||||
video) video;;
|
||||
*selected) videoselected;;
|
||||
kill) killrecording;;
|
||||
*)
|
||||
if [ -f /tmp/recordingpid ]; then
|
||||
recpid="$(cat /tmp/recordingpid)"
|
||||
if ps -p $recpid > /dev/null; then
|
||||
asktoend
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
askrecording;;
|
||||
esac
|
44
home/.local/bin/scripts/gui/dmenu-scripts/dmenuumount
Executable file
44
home/.local/bin/scripts/gui/dmenu-scripts/dmenuumount
Executable file
|
@ -0,0 +1,44 @@
|
|||
#!/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.
|
||||
|
||||
unmountusb() {
|
||||
[ -z "$drives" ] && exit
|
||||
chosen="$(echo "$drives" | dmenu -i -p "Unmount which drive?")" || exit 1
|
||||
chosen="$(echo "$chosen" | awk '{print $1}')"
|
||||
[ -z "$chosen" ] && exit
|
||||
sudo -A umount "$chosen" && notify-send "💻 USB unmounting" "$chosen unmounted."
|
||||
}
|
||||
|
||||
unmountandroid() { \
|
||||
chosen="$(awk '/simple-mtpfs/ {print $2}' /etc/mtab | dmenu -i -p "Unmount which device?")" || exit 1
|
||||
[ -z "$chosen" ] && exit
|
||||
sudo -A umount -l "$chosen" && notify-send "🤖 Android unmounting" "$chosen unmounted."
|
||||
}
|
||||
|
||||
asktype() { \
|
||||
choice="$(printf "USB\\nAndroid" | dmenu -i -p "Unmount a USB drive or Android device?")" || exit 1
|
||||
case "$choice" in
|
||||
USB) unmountusb ;;
|
||||
Android) unmountandroid ;;
|
||||
esac
|
||||
}
|
||||
|
||||
drives=$(lsblk -nrpo "name,type,size,mountpoint" | awk '$4!~/\/boot|\/home$|SWAP/&&length($4)>1{printf "%s (%s)\n",$4,$3}')
|
||||
|
||||
if ! grep simple-mtpfs /etc/mtab; then
|
||||
[ -z "$drives" ] && echo "No drives to unmount." && exit
|
||||
echo "Unmountable USB drive detected."
|
||||
unmountusb
|
||||
else
|
||||
if [ -z "$drives" ]
|
||||
then
|
||||
echo "Unmountable Android device detected."
|
||||
unmountandroid
|
||||
else
|
||||
echo "Unmountable USB drive(s) and Android device(s) detected."
|
||||
asktype
|
||||
fi
|
||||
fi
|
8
home/.local/bin/scripts/gui/dmenu-scripts/pyrun
Executable file
8
home/.local/bin/scripts/gui/dmenu-scripts/pyrun
Executable file
|
@ -0,0 +1,8 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Simple wrapper to quickly execute a simple python command and have it printed out.
|
||||
# The output is then sent back via notification.
|
||||
#
|
||||
# This already has random imported, since that's a common use-case for this script.
|
||||
|
||||
echo "" | dmenu -i -p "Python" | xargs -0 -I % python -c "import random;print(%)" | xargs -I % notify-send "Pyrun output:" "%"
|
36
home/.local/bin/scripts/gui/dmenu-scripts/todo
Executable file
36
home/.local/bin/scripts/gui/dmenu-scripts/todo
Executable file
|
@ -0,0 +1,36 @@
|
|||
#!/bin/sh
|
||||
# This is inspired by dmenu's todo script made by suckless
|
||||
#
|
||||
# Manage TODO tasks in dmenu by writing them, remove by selecting
|
||||
# an existing entry
|
||||
#
|
||||
# Configurable variables
|
||||
# ---------------------------------------------------------------------
|
||||
|
||||
FILE="${XDG_DATA_HOME:-$HOME/.local/share}/todos"
|
||||
PROMPT="Add/delete a task: "
|
||||
|
||||
# Logic
|
||||
# ---------------------------------------------------------------------
|
||||
mkdir -p "$(dirname $FILE)"
|
||||
touch "$FILE"
|
||||
|
||||
height=$(wc -l "$FILE" | awk '{print $1}')
|
||||
|
||||
# Run dmenu and keep restarting it until it returns an empty output
|
||||
cmd=$(dmenu -l "$height" -p "$PROMPT" "$@" < "$FILE")
|
||||
while [ -n "$cmd" ]; do
|
||||
# If the output matched an existing TODO, remove it
|
||||
if grep -q "^$cmd\$" "$FILE"; then
|
||||
grep -v "^$cmd\$" "$FILE" > "$FILE.$$"
|
||||
mv "$FILE.$$" "$FILE"
|
||||
height=$(( height - 1 ))
|
||||
# If the output didn't match an existing TODO, it's a new one, add it
|
||||
else
|
||||
echo "$cmd" >> "$FILE"
|
||||
height=$(( height + 1 ))
|
||||
fi
|
||||
|
||||
# Keep restarting until empty output
|
||||
cmd=$(dmenu -l "$height" -p "$PROMPT" "$@" < "$FILE")
|
||||
done
|
23
home/.local/bin/scripts/gui/dmenu-scripts/website-link
Executable file
23
home/.local/bin/scripts/gui/dmenu-scripts/website-link
Executable file
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/env python
|
||||
import feedparser
|
||||
import subprocess
|
||||
|
||||
|
||||
URL = "https://itsdrike.com/posts/index.xml"
|
||||
|
||||
|
||||
def main():
|
||||
feed = feedparser.parse(URL)
|
||||
titles = {entry['title']: entry['link'] for entry in feed['entries']}
|
||||
|
||||
selected_page = subprocess.check_output(
|
||||
["dmenu", "-i", "-p", "Post"],
|
||||
input="\n".join(titles.keys()), universal_newlines=True
|
||||
)
|
||||
link = titles[selected_page.strip()]
|
||||
|
||||
subprocess.check_output(["xsel", "-bi"], input=link, universal_newlines=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
299
home/.local/bin/scripts/gui/gh-notification
Executable file
299
home/.local/bin/scripts/gui/gh-notification
Executable file
|
@ -0,0 +1,299 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Parse arguments
|
||||
# ------------------------------------------------------------------------------------
|
||||
ALL=0
|
||||
VERBOSE=0
|
||||
VERY_VERBOSE=0
|
||||
VERY_VERY_VERBOSE=0
|
||||
TEMP_SHOW=0
|
||||
DRY_RUN=0
|
||||
NO_CACHE=0
|
||||
NO_DISPLAY=0
|
||||
URGENCY="normal"
|
||||
RESET=0
|
||||
while [ "$1" ]; do
|
||||
case "$1" in
|
||||
-h | --help)
|
||||
cat << EOF
|
||||
gh-notification is a tool that scrapes unread github notifications
|
||||
It uses github-cli with meiji163/gh-notify addon to obtain the unread notifications
|
||||
these are then parsed and sent as desktop notifications with notify-send
|
||||
|
||||
Options:
|
||||
-a | --all: Also process already read notifications
|
||||
-t | --temp-files: Show names of used temporary files for each notification
|
||||
-v | --verbose: Shows info about what's happening.
|
||||
-vv | --very-verbose: Implies --verbose, shows some more info about what's happening
|
||||
-vvv | --very-very-verbose: Implies --very-verbose and --temp-files, shows even more details, usually just for debugging
|
||||
-d | --dry-run: Run without sending any notificatinos, when ran with -r, this will also prevent any actual cache file removals
|
||||
-nc | --no-cache: Ignore the cache and send all found notifications, even if they were already sent before.
|
||||
-nd | --no-display: When the script is ran from headless mode (such as by crontab), this will still attempt to set the DISPLAY and send the desktop notification
|
||||
-r | --reset: Resets notification cache (storing which notifications were already sent), skips notification sending, WARNING: removes the whole cache, regardless of '--all')
|
||||
-u | --urgency [urgency-level]: pass over notify-send urgency attribute (low, normal, critical)
|
||||
EOF
|
||||
exit 0
|
||||
;;
|
||||
-a | --all)
|
||||
ALL=1
|
||||
;;
|
||||
-t | --temp-files)
|
||||
TEMP_SHOW=1
|
||||
;;
|
||||
-v | --verbose)
|
||||
VERBOSE=1
|
||||
;;
|
||||
-vv | --very-verbose)
|
||||
VERBOSE=1
|
||||
VERY_VERBOSE=1
|
||||
;;
|
||||
-vvv | --very-very-verbose)
|
||||
VERBOSE=1
|
||||
TEMP_SHOW=1
|
||||
VERY_VERBOSE=1
|
||||
VERY_VERY_VERBOSE=1
|
||||
;;
|
||||
-d | --dry-run)
|
||||
DRY_RUN=1
|
||||
;;
|
||||
-nc | --no-cache)
|
||||
NO_CACHE=1
|
||||
;;
|
||||
-nd | --no-display)
|
||||
NO_DISPLAY=1
|
||||
;;
|
||||
-u | --urgency)
|
||||
URGENCY="$2"
|
||||
shift
|
||||
;;
|
||||
-r | --reset)
|
||||
RESET=1
|
||||
;;
|
||||
* )
|
||||
echo "Unknown argument '$1', use -h or --help for help"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
|
||||
# Perform cache resetting, if requested
|
||||
# ------------------------------------------------------------------------------------
|
||||
if [ $RESET -eq 1 ]; then
|
||||
if [ $NO_CACHE -eq 1 ]; then
|
||||
echo "Can't ignore cache when resetting the cache..."
|
||||
exit 1
|
||||
fi
|
||||
out="$(find /tmp -maxdepth 1 -name 'gh-notification-*' 2>/dev/null)"
|
||||
total="$(printf "%s\n" "$out" | wc -l)"
|
||||
# Since we always end with a newline (to count the last entry as a line), we always get
|
||||
# at least 1 as a total here, even if $out is empty. If we didn't use the \n, we'd always
|
||||
# get 0, even if there was a single line, since it wasn't ended with a newline. To figure
|
||||
# out whether there really is a line or not when we get a total of 1, we run character
|
||||
# amount check as well
|
||||
[ "$total" -eq 1 ] && [ "$(printf "%s" "$out" | wc -c)" -eq 0 ] && total=0
|
||||
|
||||
if [ $total -gt 0 ]; then
|
||||
# Since the loop is running in a pipe, it can't modify variables, but we need to know
|
||||
# which files have failed to be removed, so to get that information, we store it in a
|
||||
# teporary file
|
||||
fail_files_file="$(mktemp)"
|
||||
|
||||
printf "%s\n" "$out" | while read -r file_name; do
|
||||
# If desired, let user know about the found notification cache file
|
||||
if [ $VERY_VERBOSE -eq 1 ] || [ $TEMP_SHOW -eq 1 ]; then
|
||||
contents="$(cat "$file_name")"
|
||||
title="$(printf "%s" "$contents" | awk -F '~@~' '{ print $1 }')"
|
||||
|
||||
echo "Found cache tempfile: '$file_name' - $title"
|
||||
if [ $VERY_VERY_VERBOSE -eq 1 ]; then
|
||||
description="$(printf "%s" "$contents" | awk -F '~@~' '{ print $2 }')"
|
||||
echo "Notification description: $description"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $DRY_RUN -ne 1 ]; then
|
||||
# In case `rm` fails, keep track of which files it failed on
|
||||
if ! rm "$file_name" 2>/dev/null; then
|
||||
printf "%s\n" "$file_name" >> "$fail_files_file"
|
||||
fi
|
||||
else
|
||||
[ $VERY_VERY_VERBOSE -eq 1 ] && echo "Tempfile removal skipped (dry-run)"
|
||||
fi
|
||||
|
||||
# Add a new-line separator on very very verbose to group prints from each iteration
|
||||
[ $VERY_VERY_VERBOSE -eq 1 ] && echo ""
|
||||
done
|
||||
|
||||
# Recover failed files from the temporary file
|
||||
failed_files="$(cat "$fail_files_file")"
|
||||
failed="$(printf "%s" "$fail_files_file" | wc -l)"
|
||||
rm "$fail_files_file"
|
||||
|
||||
if [ $VERBOSE -eq 1 ]; then
|
||||
echo "Notification cache was reset."
|
||||
removed_count="$(("$total"-"$failed"))"
|
||||
if [ $DRY_RUN -eq 1 ]; then
|
||||
echo "Removed $removed_count files (dry-run: no files were actually removed)"
|
||||
else
|
||||
echo "Removed $removed_count files"
|
||||
fi
|
||||
fi
|
||||
|
||||
# If some cache files were'nt removed successfully, inform the user about it
|
||||
# regardless of verbosity, this shouldn't go silent, even though it may be fine
|
||||
if [ "$failed" -gt 0 ]; then
|
||||
echo "WARNING: Failed to remove $failed files."
|
||||
echo "You probably don't have permission to remove these."
|
||||
echo "Perhaps these were made by someone else? If so, you can ignore this warning."
|
||||
if [ $VERBOSE -eq 0 ]; then
|
||||
echo "Run with --verbose to show exactly which files weren't removed."
|
||||
else
|
||||
echo "These are:"
|
||||
echo "$failed_files"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
[ $VERBOSE -eq 1 ] && echo "No cache files found, nothing to reset"
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
||||
# Helper functins
|
||||
# ------------------------------------------------------------------------------------
|
||||
# This runs notify-send, and if NO_DISPLAY is set and we're running in headless
|
||||
# mode, this will still try to send the notification by manually setting DISPLAY
|
||||
# This also has a special handle that checks if dunst is the notification daemon
|
||||
# in which case instead of using notify-send, we use dunstify to send the
|
||||
# notification, with which we can also specify some more values.
|
||||
send_notify() {
|
||||
if [ $NO_DISPLAY -eq 1 ]; then
|
||||
XDG_RUNTIME_DIR="/run/user/$(id -u)" \
|
||||
DISPLAY=:0 \
|
||||
notify-send --app-name=github-notification --urgency="$URGENCY" "$1" "$2"
|
||||
else
|
||||
notify-send --app-name=github-notification --urgency="$URGENCY" "$1" "$2"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# Obtain notifications and show them, if they weren't showed (aren't in cache) already
|
||||
# ------------------------------------------------------------------------------------
|
||||
# Request unread notifications with gh-notify extension for github-cli
|
||||
[ "$ALL" -eq 1 ] && out="$(gh notify -s -a)" || out="$(gh notify -s)"
|
||||
total="$(printf "%s\n" "$out" | wc -l)"
|
||||
# Since we always end with a newline (to count the last entry as a line), we always get
|
||||
# at least 1 as a total here, even if $out is empty. If we didn't use the \n, we'd always
|
||||
# get 0, even if there was a single line, since it wasn't ended with a newline. To figure
|
||||
# out whether there really is a line or not when we get a total of 1, we run character
|
||||
# amount check as well
|
||||
[ "$total" -eq 1 ] && [ "$(printf "%s" "$out" | wc -c)" -eq 0 ] && total=0
|
||||
|
||||
# Only run if we actually found some notifications
|
||||
if [ "$total" -gt 0 ]; then
|
||||
# Since the loop is running in a pipe, it can't modify variables, but we need to know
|
||||
# how many notifications were sent, so to ge that information, we store it in a
|
||||
# temporary file
|
||||
sent_count_file="$(mktemp)"
|
||||
printf "0" > "$sent_count_file"
|
||||
|
||||
# Go through each notification, one by one
|
||||
printf "%s\n" "$out" | while read -r line; do
|
||||
# Parse out the data from given output lines
|
||||
issue_type="$(echo "$line" | awk '{print $4}' | sed 's/\x1b\[[0-9;]*m//g')"
|
||||
repo_id="$(echo "$line" | awk '{print $3}' | sed 's/\x1b\[[0-9;]*m//g')"
|
||||
|
||||
|
||||
if [ "$issue_type" == "PullRequest" ]; then
|
||||
issue_id="$(echo "$line" | awk '{print $5}' | sed 's/\x1b\[[0-9;]*m//g' | cut -c2-)"
|
||||
description="$(echo "$line" | awk '{for (i=6; i<NF; i++) printf $i " "; print $NF}' | sed 's/\x1b\[[0-9;]*m//g')"
|
||||
name="$repo_id ($issue_type #$issue_id)"
|
||||
|
||||
url="https://github.com/$repo_id/pull/$issue_id"
|
||||
elif [ "$issue_type" == "Issue" ]; then
|
||||
issue_id="$(echo "$line" | awk '{print $5}' | sed 's/\x1b\[[0-9;]*m//g' | cut -c2-)"
|
||||
description="$(echo "$line" | awk '{for (i=6; i<NF; i++) printf $i " "; print $NF}' | sed 's/\x1b\[[0-9;]*m//g')"
|
||||
name="$repo_id ($issue_type #$issue_id)"
|
||||
|
||||
url="https://github.com/$repo_id/issues/$issue_id"
|
||||
elif [ "$issue_type" == "Release" ]; then
|
||||
# There's no issue ID with github releases, they just have a title
|
||||
# this means if the name is the same, they will be treated as the same release
|
||||
# and they could end up being ignored, this could be fixed by using github API and
|
||||
# searching for that release's commit, but that's too much work here for little benefit
|
||||
description="$(echo "$line" | awk '{for (i=5; i<NF; i++) printf $i " "; print $NF}' | sed 's/\x1b\[[0-9;]*m//g')"
|
||||
name="$repo_id ($issue_type)"
|
||||
|
||||
# Because we don't know the tag or commit ID, best we can do is use the page for all releases
|
||||
# the new release will be the first one there anyway
|
||||
url="https://github.com/$repo_id/releases"
|
||||
else
|
||||
echo "Unknown issue type: '$issue_type'!"
|
||||
echo "Can't construct URL, falling back to just repository URL."
|
||||
echo "Please report this issue to ItsDrike/dotfiles repository."
|
||||
url="https://github.com/$repo_id"
|
||||
fi
|
||||
|
||||
[ $VERY_VERBOSE -eq 1 ] && echo "Found notification $name"
|
||||
[ $VERY_VERY_VERBOSE -eq 1 ] && echo "Description: $description"
|
||||
[ $VERY_VERY_VERBOSE -eq 1 ] && echo "Constructed url: $url"
|
||||
|
||||
# Create hash from the name and description and use it to construct
|
||||
# a path to a temporary file
|
||||
# To keep this POSIX compliant, we can't use <<< to feed a string to the
|
||||
# sum function, so we're using another temporary file which is then removed
|
||||
temp_file="$(mktemp)"
|
||||
printf "$name$description" > "$temp_file"
|
||||
hashsum="$(sum < "$temp_file" | cut -f 1 -d ' ')"
|
||||
rm "$temp_file"
|
||||
|
||||
tmpname="/tmp/gh-notification-$hashsum"
|
||||
[ $TEMP_SHOW -eq 1 ] && echo "Tempfile: $tmpname"
|
||||
|
||||
# If the temporary file is already present, this notification was already
|
||||
# send and we don't want to re-send it
|
||||
|
||||
# Only sent the notification if it wasn't already cached (doesn't have temp file)
|
||||
# this avoids resending the same notifications
|
||||
if [ ! -e "$tmpname" ] || [ $NO_CACHE -eq 1 ]; then
|
||||
if [ $DRY_RUN -eq 1 ]; then
|
||||
[ $VERY_VERBOSE -eq 1 ] && echo "Sending notification (dry-run, no actual notification was sent)"
|
||||
else
|
||||
[ $VERY_VERBOSE -eq 1 ] && echo "Sending notification"
|
||||
send_notify "$name" "$description <$url>"
|
||||
# Create the tempfile so that in the next run, we won't resend this notification again
|
||||
# NOTE: We're storing the name and description into this file to make it easier
|
||||
# to figure out what notification the tempfile belongs to, with ~@~ separator
|
||||
printf "%s~@~%s" "$name" "$description" > "$tmpname"
|
||||
fi
|
||||
# Keep track of how many notifications were sent (didn't have a cache file)
|
||||
sent="$(cat "$sent_count_file")"
|
||||
sent="$(("$sent"+1))"
|
||||
printf "%s" "$sent" > "$sent_count_file"
|
||||
else
|
||||
[ $VERY_VERBOSE -eq 1 ] && echo "Skipping (cached) - notification already sent"
|
||||
fi
|
||||
|
||||
# Add a new-line separator on very verbose to group prints from each iteration
|
||||
[ $VERY_VERBOSE -eq 1 ] && echo ""
|
||||
done
|
||||
|
||||
# Recover amount of sent notifications from the temporary file
|
||||
sent="$(cat "$sent_count_file")"
|
||||
rm "$sent_count_file"
|
||||
|
||||
if [ $VERBOSE -eq 1 ]; then
|
||||
unsent="$(("$total"-"$sent"))"
|
||||
if [ "$sent" -eq "$total" ]; then
|
||||
echo "Found and sent $total new notifications"
|
||||
elif [ "$unsent" -eq "$total" ]; then
|
||||
echo "Found $total notifications, all of which were already sent (no new notifications to send)"
|
||||
else
|
||||
echo "Found $total notifications, of which $sent were new and sent ($unsent were skipped - cached/already sent)"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
[ $VERBOSE -eq 1 ] && echo "No new notifications"
|
||||
fi
|
35
home/.local/bin/scripts/gui/setbg
Executable file
35
home/.local/bin/scripts/gui/setbg
Executable file
|
@ -0,0 +1,35 @@
|
|||
#!/bin/sh
|
||||
|
||||
# This script does the following:
|
||||
# Run by itself, set the wallpaper
|
||||
# If given a file, set that as the new wallpaper
|
||||
# If given a directory, recursively choose a random file in it.
|
||||
|
||||
# Location of the symlink to wallpaper image
|
||||
bgloc="${XDG_DATA_HOME:-$HOME/.local/share}/background"
|
||||
|
||||
trueloc="$(readlink -f "$1")" &&
|
||||
case "$(file --mime-type -b "$trueloc")" in
|
||||
image/* )
|
||||
ln -sf "$(readlink -f "$1")" "$bgloc"
|
||||
notify-send -i "$bgloc" "Changing wallpaper..."
|
||||
;;
|
||||
inode/directory )
|
||||
randimg="$(find -L $trueloc -iregex '.*.\(jpg\|jpeg\|png\|gif\)' -type f | shuf -n 1)"
|
||||
echo $randimg
|
||||
ln -sf "$randimg" "$bgloc"
|
||||
notify-send -i "$bgloc" "Random Wallpaper chosen."
|
||||
;;
|
||||
*)
|
||||
notify-send "Error" "Not a valid image."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Use xwallpaper to set the background
|
||||
if [ "$XDG_SESSION_TYPE" == "wayland" ]; then
|
||||
killall swaybg 2>/dev/null
|
||||
swaybg --image "$bgloc" & disown
|
||||
else
|
||||
xwallpaper --zoom "$bgloc"
|
||||
fi
|
Loading…
Add table
Add a link
Reference in a new issue