scripts reorganize

This commit is contained in:
2026-10-06 22:34:05 +02:00
parent a2a056a68d
commit 0734bee219
60 changed files with 824 additions and 5 deletions

View File

@@ -0,0 +1,11 @@
#!/usr/bin/env bash
# This script sends a quick notification through dunst, informing the user about the backlight of their screen
brightness=$(brightnessctl -m | awk -F, '{print $4}')
dunstify -u low \
-a Backlight \
-r 88 \
-i ~/.icons/candy-icons/apps/scalable/lightbeat.svg \
"Screen brightness is $brightness"

View File

@@ -0,0 +1,19 @@
#!/usr/bin/env fish
# This script switches the wallpaper to a random image found under ~/Pictures/wallpapers
# Supports i3, Hyprland, and Sway.
switch "$XDG_CURRENT_DESKTOP"
case i3
feh --bg-fill (find ~/Pictures/wallpapers -type f -regextype posix-extended -iregex "/(.*/)*[^\.]*\.(png|jpe?g|webp)" | sort -R | head -n1)
case sway Hyprland
swaybg -i (find ~/Pictures/wallpapers -type f | sort -R | head -n1) &
set newpid $last_pid
sleep 0.2
for pid in (pgrep -x swaybg)
if test $pid -ne $last_pid
kill $pid
end
end
end

27
scripts/WMScripts/dunst.sh Executable file
View File

@@ -0,0 +1,27 @@
#!/usr/bin/env bash
# toggles dunstctl + sends a message (thru dounst ironically)
lvl=$(dunstctl get-pause-level)
send_msg() {
dunstify -u low \
-a Backlight \
-r 92 \
-i ~/.icons/candy-icons/apps/scalable/cliq.svg \
"Toggled dunst $1"
}
if [[ $lvl == "0" ]]; then
# dunst is currently enabled; send message first then disable
dunstctl close-all
# send_msg "off"
# sleep 2
dunstctl set-paused toggle
else
# dunst is currently disabled; enable then send message
dunstctl set-paused toggle
# send_msg "on"
fi

42
scripts/WMScripts/dunst_bar.py Executable file
View File

@@ -0,0 +1,42 @@
#!/usr/bin/env nix-shell
#! nix-shell -i python3 --packages python314Packages.dbus-fast
from asyncio import run, Event
from json import dumps
from dbus_fast.aio import MessageBus
from dbus_fast.proxy_object import BaseProxyInterface, BaseProxyObject
def update_dbus_state(interface, changed, _) -> None:
if interface != 'org.dunstproject.cmd0':
return
if 'paused' in changed:
update_output(changed['paused'].value)
def update_output(paused: bool) -> None:
print(dumps({
"text": "󱙍" if paused else "󰍡",
"alt": "",
"tooltip": "",
"class": "muted-notifs" if paused else "unmuted-notifs",
"percentage": 0
}, ensure_ascii=False))
async def main() -> None:
bus = await MessageBus().connect()
introspection = await bus.introspect('org.freedesktop.Notifications', '/org/freedesktop/Notifications')
notifications: BaseProxyObject = bus.get_proxy_object('org.freedesktop.Notifications', '/org/freedesktop/Notifications', introspection)
properties = notifications.get_interface('org.freedesktop.DBus.Properties')
dunst = notifications.get_interface('org.dunstproject.cmd0')
properties.on_properties_changed(update_dbus_state)
update_output(await dunst.get_paused())
await Event().wait()
if __name__ == "__main__":
run(main())

78
scripts/WMScripts/exit.sh Executable file
View File

@@ -0,0 +1,78 @@
#!/usr/bin/env sh
# This script cleanly exits a variety of window managers, depending on the given parameters
# Also checks no windows exist on the scratchpad (as I tend to forget about those)
case "$XDG_CURRENT_DESKTOP" in
"Hyprland")
lock="hyprlock"
cmd="hyprctl clients -j | jq . | grep -E 'special' -c"
ctl="hyprctl dispatch"
logout="uwsm stop"
;;
"sway")
lock="swaylock --screenshots --clock --indicator --indicator-radius 100 --indicator-thickness 7 --effect-pixelate 25 -- effect-vignette 0.5:0.5 --ring-color 244273a --key-hl-color c6a0f6 --line-color 00000000 --inside-color 00000000 --separator-color 00000000"
cmd="swaymsg -rt get_tree | jq . | grep -E 'scratchpad_state\": \"(changed|fresh)' -c"
ctl="swaymsg"
logout="swaymsg exit"
;;
"i3")
lock='i3lock -n -c 18192666 -k --radius 180 --inside-color=24273a --layout-color=cad3f5 --time-color=cad3f5 --date-color=cad3f5 --greeter-color=cad3f5 --verif-color=cad3f5 --wrong-color=cad3f5 --modif-color=cad3f5 --ring-color=c6a0f6 --insidever-color=24273a --ringver-color=8aadf4 --insidewrong-color=24273a --ringwrong-color=ed8796 --keyhl-color=a6da95 --bshl-color=f5a97f --separator-color=24273a --date-str="%A, %d %B %Y"'
cmd="i3-msg -t get_tree | jq . | grep -E 'scratchpad_state\": \"(changed|fresh)' -c"
ctl="i3-msg"
logout="i3-msg exit"
;;
*)
dunstify -u low -t 2000 -i ~/.icons/candy-icons/apps/scalable/system-shutdown.svg "This desktop is not supported."
exit
;;
esac
spec_exist() {
n=$(eval "$cmd")
if [ "$n" -gt 0 ]; then
[ "$n" -gt 1 ] && msg="$n windows" || msg="window"
dunstify -t 3000 \
-u low \
-i ~/.icons/candy-icons/apps/scalable/system-shutdown.svg \
-a i3exit \
"Close the $msg in the scratchpad first."
exit 0
fi
}
lock() {
dunstctl set-paused true
bash -c "$lock"
dunstctl set-paused false
}
case "$1" in
lock)
lock
;;
logout)
eval "$logout"
;;
suspend)
systemctl suspend && lock
;;
hibernate)
systemctl hibernate && lock
;;
reboot)
spec_exist
systemctl reboot
;;
shutdown)
spec_exist
systemctl poweroff
;;
*)
echo "Usage: $0 {lock|logout|suspend|hibernate|reboot|shutdown}"
exit 2
esac
exit 0

View File

@@ -0,0 +1,21 @@
#!/usr/bin/env sh
# launch a new kitty window.
# If a kitty window is active, sets the new CWD to the current one.
# Else just launch a new one.
case "$XDG_CURRENT_DESKTOP" in
"Hyprland")
pid=$(hyprctl activewindow -j | jq '. | if .initialTitle == "kitty" then .pid else -1 end')
;;
*)
pid="-1"
;;
esac
if [[ "$pid" == "-1" ]]; then
kitty &
else
kitten @ --to unix:@kitty-$pid launch --cwd current --type os-window &
fi

18
scripts/WMScripts/microphone.sh Executable file
View File

@@ -0,0 +1,18 @@
#!/usr/bin/env bash
# This script updates the microphone custom module of my specific polybar setup
case "$XDG_CURRENT_DESKTOP" in
"sway"|"Hyprland")
"$(dirname "$0")/microphone_bar.sh" mute
kill -n36 $(pgrep waybar)
;;
"i3")
polybar-msg -p "$(xdotool search --name polybar-default getwindowpid)" action "#microphone.hook.0"
polybar-msg -p "$(xdotool search --name polybar-secondary getwindowpid)" action "#microphone.hook.1"
;;
*)
dunstify -u low -t 2000 -i ~/.icons/candy-icons/apps/scalable/pavucontrol.svg "Current desktop is not supported by microphone.sh"
exit
;;
esac

View File

@@ -0,0 +1,41 @@
#!/usr/bin/env bash
MUTE=" "
NORMAL=""
output () {
case "$XDG_CURRENT_DESKTOP" in
"sway"|"Hyprland")
if [[ -n "$1" ]]; then
echo "{\"text\": \"$NORMAL\", \"alt\": \"\", \"tooltip\": \"\", \"class\": \"unmuted-mike\", \"percentage\": 0}"
else
echo "{\"text\": \"$MUTE\", \"alt\": \"\", \"tooltip\": \"\", \"class\": \"muted-mike\", \"percentage\": 0}"
fi
;;
"i3")
if [[ -n "$1" ]]; then
echo "$NORMAL"
else
echo "%{F#707880}$MUTE%{T- F-}"
fi
;;
*)
dunstify -t 2000 -u low -i ~/.icons/candy-icons/apps/scalable/noisetorch.svg "This desktop is not supported."
exit
;;
esac
}
if [[ "$1" == "mute" ]]; then
amixer sset Capture toggle > /dev/null
fi
STATUS=$(amixer get Capture | tail -n1 | awk '{print $5}' -)
case $STATUS in
"[on]")
output "yes"
;;
*)
output
;;
esac

28
scripts/WMScripts/murder.sh Executable file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env bash
# This script allows the user to select a window
# then nicely asks it to shut down (SIGTERM).
# if the window does not shut down, it is murdered instead (SIGKILL)
case "$XDG_CURRENT_DESKTOP" in
"Hyprland")
id=$(hyprprop | jq '.pid')
;;
"sway")
id=$(wlprop | jq '.pid')
;;
"i3")
id=$(xprop _NET_WM_PID | awk '{print $3}')
;;
*)
dunstify -u low -t 2000 -i ~/.icons/candy-icons/apps/scalable/clamav.svg "This session type is not supported by murder.sh"
exit
esac
[[ ! "$id" =~ [0-9]+ ]] && exit
kill "$id"
sleep 2
if [[ $(ps -p "$id" 2>&1 > /dev/null) -ne 0 ]]; then
kill -s 9 "$id"
fi

View File

@@ -0,0 +1,73 @@
#!/usr/bin/env bash
# mutes the pipewire sink of the active window, if we can find it.
# $1: if non-empty, applies the specified shader
# 1: get activewindow pid
# 2 match to pactl source
# 2a: try directly against pid
# 2b: if fails: run through fallbacks for specific windows
# 3 toggle pactl source mute
# 4 set window tag for custom shading
# Toggle mute a pactl sink
# $1 int: id of sink to toggle
function toggle_sink {
pactl set-sink-input-mute "$1" toggle
}
# Toggle mute for an array of pactl sinks
# $1 string: space separated list of sink ids
function toggle_multiple {
for i in $1; do
toggle_sink "$i"
done
}
case "$XDG_CURRENT_DESKTOP" in
"Hyprland")
activePid=$(hyprctl activewindow -j | jq ".pid")
tagCmd="hyprctl dispatch 'hl.dsp.window.tag({ tag = \"shader/$1\" })'"
class=$(hyprctl activewindow -j | jq ".class")
;;
*)
dunstify -u low -t 2000 -i ~/.icons/candy-icons/apps/scalable/yast-sound.svg "muteActive does not support the current desktop."
exit
;;
esac
sinks=$(pactl -f json list sink-inputs)
binary=$(ps -q "$activePid" -o comm=)
mutableSinks=$(printf "%s" "$sinks" | jq -r ".[] | select(.properties.\"application.process.id\" == \"$activePid\") | .index")
# fallbacks
[[ -z "$mutableSinks" ]] && mutableSinks=$(printf "%s" "$sinks" | jq -r ".[] | select(.properties.\"application.process.binary\" == \"$binary\") | .index") # Feishin
[[ -z "$mutableSinks" ]] && mutableSinks=$(printf "%s" "$sinks" | jq -r ".[] | select(.properties.\"application.id\" == \"$binary\") | .index") # mpv
[[ -z "$mutableSinks" && "$class" = \"tf_linux64\" ]] && mutableSinks=$(printf "%s" "$sinks" | jq -r ".[] | select(.properties.\"application.name\" == \"tf_linux64\" ) .index") # tf2
if [[ -z "$mutableSinks" ]]; then
# still no matched sink; give up
printf "Couldn't match activeWindow to any pipewire sinks!\n"
dunstify -u low \
-a Mute \
-r 35 \
-i ~/.icons/candy-icons/apps/scalable/yast-sound.svg \
"Could not match active window to pipewire input"
exit 1
else
printf "Matched activeWindow | class | %s\n |binary| %s\n | sink | %s | to pipewire sink" "$class" "$binary" "$mutableSinks" | column -ts '|'
dunstify -u low \
-a Mute \
-r 35 \
-i ~/.icons/candy-icons/apps/scalable/yast-sound.svg \
"Toggled mute on active window"
fi
toggle_multiple "$mutableSinks"
[ -n "$1" ] && eval "$tagCmd"

75
scripts/WMScripts/record.sh Executable file
View File

@@ -0,0 +1,75 @@
#!/usr/bin/env bash
# This script allows one to record a slected area of the screen.
# Calling the script again will end recording, and save the file to
# ~/Videos/screen captures/$(date +%F_%T).mp4
# create directory if necessary
mkdir -p ~/Videos/screen\ captures
# variables
record_file="/tmp/record_file"
now="$(date +%F_%T)"
file="$HOME/Videos/screen captures/$now.mp4"
stop_recording () {
kill -2 "$(head -1 $record_file)"
kill -KILL "$(head -2 $record_file | tail -n1 )"
old_date="$(cat $record_file | tail -n1)"
rm "$record_file"
# notif
dunstify -u low \
-a Record \
-r 8827 \
-i ~/.icons/candy-icons/apps/scalable/simplescreenrecorder.svg \
"Saved recording to $old_date.mp4"
echo "Saved recording to $old_date.mp4"
}
start_recording () {
case "$XDG_SESSION_TYPE" in
x11)
# get coordinates
slop=$(slop -f "%x %y %w %h %g %i") || exit 1
read -r X Y W H G ID <<< "$slop"
# record screen
ffmpeg -v 1 -r 30 -f x11grab -s "$W"x"$H" -i :0.0+"$X","$Y" -show_region 1 -vf "scale=2*trunc(iw/2):2*trunc(ih/2)" -vcodec libx264 -pix_fmt yuv420p -preset ultrafast -crf 18 -threads 0 "$file" -y &
;;
wayland)
# get coordinates
if ! slurp="$(slurp)"; then
exit
fi
wf-recorder -g "$slurp" -f "$file" --framerate 30 &
;;
*)
dunstify -t 2000 -u low -i ~/.icons/candy-icons/apps/scalable/camorama.svg "This session type is not supported by record.sh"
exit
;;
esac
# print metadata to tmp file
echo $! > "$record_file"
echo $$ >> "$record_file"
echo "$now" >> "$record_file"
# loop notif
i=0
while :; do
i=$(($i + 1))
dunstify -u low \
-a Record \
-r 8827 \
-i ~/.icons/candy-icons/apps/scalable/simplescreenrecorder.svg \
"Recording for $(date -d@$i -u +%H:%M:%S)"
sleep 1
done
}
[[ -e "$record_file" ]] && stop_recording || start_recording

View File

@@ -0,0 +1,47 @@
#!/usr/bin/env bash
# This script allows the user to make a screenshot (through flameshot)
# and will then open said screenshot from the clipboard into feh
# it will also make the feh window floating
case "$XDG_CURRENT_DESKTOP" in
"Hyprland")
paste="wl-paste -t image/png"
move () {
bash -c "hyprctl dispatch 'hl.dsp.window.move({ x = \"$1\", y = \"$2\", relative = false})'"
}
;;
"sway")
paste="wl-paste -t image/png"
move () {
bash -c "swaymsg move absolute position $1 $2"
}
;;
"i3")
paste="xclip -selection clipboard -t image/png -o"
move () {
bash -c "i3-msg move position $1 $2"
}
;;
*)
dunstify -t 2000 -u low -i ~/.icons/candy-icons/apps/scalable/image-viewer.svg "Current desktop is not supported by floatshot."
exit
;;
esac
out=$(flameshot gui -g)
# If the capture was cancelled, out will be empty
if [[ -n "$out" ]]; then
# get x,y of selection
x=$(echo "$out" | awk -F'+' '{print $2}')
y=$(echo "$out" | awk -F'+' '{print $3}')
bash -c "$paste" | feh - -T notitle --class 'floatme' &
pid="$!"
while [[ -z $(wmctrl -lp | awk -vpid=$pid '$3==pid {print $1; exit}') ]]; do
sleep 0.05
done
move "$x" "$y"
fi

36
scripts/WMScripts/tess.sh Executable file
View File

@@ -0,0 +1,36 @@
#!/usr/bin/env bash
# This script allows the user to make a selection, then runs that selection through OCR and copies the result to clipboard
case "$XDG_SESSION_TYPE" in
"wayland")
copy="wl-copy"
screenshot="grim -g"
slop=$(slurp -f "%x,%y %wx%h") || exit 1
;;
"x11")
copy="xclip -selection c"
screenshot="import -window root -crop "
slop=$(slop -f "%G") || exit 1
;;
*)
dunstify -t 2000 -u low -i ~/.icons/candy-icons/apps/scalable/code.svg "Current session type not supported by tess.sh"
exit
;;
esac
# files
imagefile="/tmp/tesseract.$RANDOM.png"
text="/tmp/translation"
# get screenshot
read -r G <<< "$slop"
bash -c "$screenshot \"$G\" $imagefile"
# OCR, save to clipboard
tesseract $imagefile $text 2>/dev/null
cat "$text.txt" | bash -c "$copy"
# cleanup
rm $text".txt"
rm "$imagefile"

View File

@@ -0,0 +1,38 @@
#!/usr/bin/env bash
# This script updates the clementine and combine toggle custom modules of my specific polybar setup
case "$XDG_CURRENT_DESKTOP" in
"sway"|"Hyprland")
case "$1" in
"clementine")
"$(dirname "$0")/toggle_audiocables_bar.sh" toggle clementine
kill -37 $(pgrep waybar)
;;
"combine")
"$(dirname "$0")/toggle_audiocables_bar.sh" toggle combine
kill -37 $(pgrep waybar)
;;
*)
echo "Unknown sink specified."
;;
esac
;;
"i3")
case "$1" in
"clementine")
polybar-msg -p "$(xdotool search --name polybar-default getwindowpid)" action "#audiocables.hook.0"
;;
"combine")
polybar-msg -p "$(xdotool search --name polybar-default getwindowpid)" action "#audiocables.hook.1"
;;
*)
echo "unknown sink specified."
;;
esac
;;
*)
dunstify -u low -t 2000 -i ~/.icons/candy-icons/apps/scalable/pavucontrol.svg "Current desktop is not supported by audiocables.sh"
exit
;;
esac

View File

@@ -0,0 +1,112 @@
#!/usr/bin/env bash
# This script toggles state between a few of my audio cables:
# combine sink -> default_output | hyperx_output
# clementine sink -> combine sink | default_output
# The script also outputs a symbol indicating which configuration is active.
# Usecase: My USB-C headset is a different sink than the one in the laptop; sometimes I want to have audio over the headset, sometimes through the laptop.
# Output symbols
# SYMBOLS=("neither" "co^!cl" "cl^!co" "both")
SYMBOLS=("󰴸 " "󰝚 " "󰓃 " "󰋋 ")
# The sinks to test against
DEFAULT_SINKS=("bluez_output_internal.0A_E6_E0_F9_F1_BE.1" "alsa_output.pci-0000_06_00.6.analog-stereo" "bluez_output.20_18_5B_F0_FC_4A.1" "bluez_output.0A_E6_E0_F9_F1_BE.1" "bluez_output.0A_E6_E0_F9_F1_BE" "bluez_output.0A:E6:E0:F9:F1:BE")
USB_C_SINK="alsa_output.usb-HP__Inc_HyperX_Cloud_III_Wireless_0000000000000000-00.analog-stereo"
COMBINE_SINK="combine"
# awkcommand - a little complicated, but basically tests if the DEFAULT_SINK is connected to the clementine sink (adding +2 if so) or the combine sink (adding +1). This gives a numerical mapping for all 4 states im interested in:
# 0: neither combine,clementine are attached to usb_c_sink
# 1: only combine is attached to usb_c_sink
# 2: only clementine is attached to usb_c_sink
# 3: both combine,clementine are attached to usb_c_sink
read -r -d "" awkcommand << EOF
/$USB_C_SINK:playback_FL/,/$USB_C_SINK:playback_FR/ {
if (\$2 == "combine:monitor_FL") {
state += 1
}
}
/$COMBINE_SINK:playback_FL/,/$COMBINE_SINK:playback_FR/ {
if (\$2 == "clementine:monitor_FL") {
state += 2
}
}
END {
printf "%d\n", state
}
EOF
# Attaches a single sink to a specific source
function attach() {
echo "attaching $1 to $2"
pw-link "$1":monitor_FL "$2":playback_FL
pw-link "$1":monitor_FR "$2":playback_FR
}
# Attaches an array of sinks to a specific source.
# $1 = source (pw monitor)
# $2 = list of sinks to attach
function attachArray() {
name=$2[@]
a=("${!name}")
for sink in "${a[@]}"; do
attach "$1" "$sink"
done
}
# Detaches a single sink from a specific source
function detach() {
echo "detaching $1 from $2"
pw-link -d "$1":monitor_FL "$2":playback_FL
pw-link -d "$1":monitor_FR "$2":playback_FR
}
# Detaches an array of sinks to a specific source.
# $1 = source (pw monitor)
# $2 = list of sinks to attach
function detachArray() {
name=$2[@]
a=("${!name}")
for sink in "${a[@]}"; do
detach "$1" "$sink"
done
}
state=$(pw-link -li | awk "$awkcommand")
IFS=$'\n'
# actually toggle iff we have a $1 telling us to
if [[ "$1" == "toggle" ]];then
case "$2" in
"clementine")
if [[ $state -eq 2 || $state -eq 3 ]]; then
detach "clementine" "$COMBINE_SINK"
attachArray "clementine" "DEFAULT_SINKS"
state=$((state-2))
else
detachArray "clementine" "DEFAULT_SINKS"
attach "clementine" "$COMBINE_SINK"
state=$((state+2))
fi
;;
"combine")
if [[ $state -eq 1 || $state -eq 3 ]]; then
detach "combine" "$USB_C_SINK"
attachArray "combine" "DEFAULT_SINKS"
state=$((state-1))
else
detachArray "combine" "DEFAULT_SINKS"
attach "combine" "$USB_C_SINK"
state=$((state+1))
fi
;;
*)
echo "Unknown option: '$2'"
;;
esac
fi
echo "${SYMBOLS[$state]}"

View File

@@ -0,0 +1,8 @@
case Hyprland
hyprctl dispatch 'hl.dsp.focus({ direction = "left" })'
for i in (ls | grep "$argv[1]")
sleep 0.05
copy "$i"
sleep 0.05
hyprctl dispatch 'hl.dsp.send_shortcut({ mods = "CTRL", key = "v" })'
end

View File

@@ -0,0 +1,6 @@
switch "$XDG_SESSION_TYPE"
case wayland
echo "file://$(realpath -- "$argv")" | wl-copy -t text/uri-list
case x11
echo "file://$(realpath -- "$argv")" | xclip -i -selection clipboard -t text/uri-list
end

View File

@@ -0,0 +1,9 @@
if test -z "$argv[1]"
set dir '.'
else
set dir "$argv[1]"
end
for i in (find "$dir" -maxdepth 1 -type d )
set b (find "$i" -type f| wc -l)
printf "%d/%s\n" $b (basename "$i")
end | sort -nr | column -ts/

View File

@@ -0,0 +1,4 @@
set dest "$(fzf)"
if test $status -eq 0
cd "$(realpath (dirname "$dest"))"
end

View File

@@ -0,0 +1,3 @@
string match -qr '^(exit|ls$|clear)' -- $argv
and history delete --exact --case-sensitive -- (string trim -r $argv)

View File

@@ -0,0 +1 @@
rename.sh "$argv"

View File

@@ -0,0 +1,5 @@
if test -n "$argv"
eval "nix-shell --run fish -p" (string join -- " -p " $argv)
else
nix-shell --run fish
end

View File

@@ -0,0 +1,2 @@
echo (cat -- "$argv")
fish -c (cat -- "$argv")

View File

@@ -0,0 +1,6 @@
if test -n "$argv[2]"
echo (cat -- "$argv[1]" | sed -n $argv[2]p)
fish -c (cat -- "$argv[1]" | sed -n $argv[2]p)
else
cat -n -- "$argv[1]"
end

View File

@@ -0,0 +1,2 @@
tr -dc A-Za-z0-9 </dev/urandom | head -c 32
echo

View File

@@ -0,0 +1 @@
perl -e 'foreach $a(@ARGV){print "\e[48:2::".join(":",unpack("C*",pack("H*",$a)))."m \e[49m "};print "\n"' "$argv"

View File

@@ -0,0 +1,6 @@
if test "$argv" = !!
echo sudo $history[1]
eval command sudo $history[1]
else
command sudo $argv
end

View File

@@ -0,0 +1,7 @@
if set -q TMUX
set -l name (tmux display -p '#{session_name}')
if test -n "$name"; and string match -qr '^[0-9]+' -- $name
set num (string match -rim 1 "[0-9]*" -- $name)
tmux rename-session "$num: cmd: $argv[1]" 2>/dev/null
end
end

View File

@@ -0,0 +1,7 @@
set tempfile (mktemp -t "yazi-cwd.XXX")
command yazi $argv --cwd-file=$tempfile
if read -z cwd < "$tempfile"; and [ "$cwd" != "$PWD" ]; and test -d "$cwd"
builtin cd -- "$cwd"
end
command rm -f -- "$tempfile"

66
scripts/hypr-scripts/bg.fish Executable file
View File

@@ -0,0 +1,66 @@
#!/usr/bin/env fish
# This script randomly switches the background (through fehbg) every 5 to 30 minutes.
# It selects a random image from the ~/Pictures/Wallpapers folder (including subdirectories)
# Any hidden files in this folder are excluded.
# in-place awk script
set awkcommand '
BEGIN {
FS=", "
width=1920
height=1080
}
NR == 1 {
x = $1
y = $2
if (x < 0) {
x = width + x
}
if (y < 0) {
y = height + y
}
print x "," y
}
'
# kill old instances
for i in (ps -C (basename (status filename)) | awk 'FNR>1 {print $1}')
if test $i -ne $fish_pid
kill $i
end
end
# set bg
swaybg -i $(find ~/Pictures/wallpapers -type f -regextype posix-extended -iregex "/(.*/)*[^\.]*\.(png|jpe?g|webp|gif)" | sort -R | head -n1)
while true
set rand (math "(floor $(random 300 1800) / 60) * 60")
# countdown
while test $rand -gt 0
set minutes (math "floor $rand / 60 ")
printf '\r\033[K%.2d:00' $minutes
sleep 60
set rand (math $rand - 60 )
end
# update wallpaper
swaybg -i $(find ~/Pictures/wallpapers -type f -regextype posix-extended -iregex "/(.*/)*[^\.]*\.(png|jpe?g|webp|gif)" | sort -R | head -n1)
set newpid $last_pid
sleep 0.2
for pid in (pgrep -x swaybg)
if test $pid -ne $last_pid
kill $pid
end
end
end

View File

@@ -0,0 +1,15 @@
#!/usr/bin/env sh
HYPRGAMEMODE=$(hyprctl getoption animations:enabled | awk 'NR==1{print $2}')
GAMING_PROFILE="GAMEINK"
if [ "$HYPRGAMEMODE" = "true" ] ; then
hyprctl eval 'hl.config({ animations = { enabled = false }, decoration = { blur = { enabled = false}, rounding = 0, shadow = { enabled = false }, fullscreen_opacity = 1}, general = { border_size = 1, gaps_in = 0, gaps_out = 0}})'
tailor profile set "$GAMING_PROFILE"
dunstify -r 55421 -t 2000 -u low -i ~/.icons/candy-icons/apps/scalable/teamspeak.svg "Gamemode on"
exit
else
dunstify -r 55421 -t 2000 -u low -i ~/.icons/candy-icons/apps/scalable/teamspeak.svg "Gamemode off"
hyprctl reload
exit 0
fi

View File

@@ -0,0 +1,25 @@
#!/usr/bin/env bash
# Toggles the GAMING_PROFILE tuxedo power profile
GAMEMODE=$(tailor profile list | grep active | cut --fields 1 -d' ')
GAMING_PROFILE="GAMEINK"
DEFAULT_PROFILE="HOTHOTHOT"
function failure() {
dunstify -r 55422 -t 4000 -u normal -i ~/.icons/candy-icons/apps/scalable/teamspeak.svg "Failed to toggle power profile!"
exit 1
}
if [[ "$GAMEMODE" =~ "GAMEINK" ]] ; then
# Default profile
tailor profile set "$DEFAULT_PROFILE" || failure
dunstify -r 55422 -t 2000 -u low -i ~/.icons/candy-icons/apps/scalable/teamspeak.svg "Gaming power profile deactivated"
exit 0
else
# gaming profile
tailor profile set "$GAMING_PROFILE" || failure
dunstify -r 55422 -t 2000 -u low -i ~/.icons/candy-icons/apps/scalable/teamspeak.svg "Gaming power profile activated"
hyprctl reload
exit 0
fi

View File

@@ -0,0 +1,75 @@
#!/usr/bin/env bash
# This script visualizes all keybindings in the hyprland config.
# It also executes the associated command, if a keybinding is selected.
# It uses an Awk script, column -t, and rofi-dmenu to do so.
# Furthermore, rofi-dmenu expects the file ~/.config/rofi/keybinds.rasi to exist for theming.
# Awk script used for parsing `hyprctl binds`
# Basically:
# $1 contains submap; if empty replace with Default; also replaces shutdown mode.
# $2 contains modmap; parsed and replaced with human-readable modifiers
# $3 contains key
# $4 contains description
awkcommand='
BEGIN {
FS="\t"
}
{
# submap
if ($1 == "") {
submap = "Default"
} else {
submap = $1
if (submap == "l e s h r ^s") {
submap = "Shutdown"
}
}
# modmap parse
modmap = $2
mods = "1"
if (modmap >= 64) {
mods = gensub(/1/, " 1", 1, mods)
modmap = modmap - 64
}
if (modmap >= 8) {
mods = gensub(/1/, "Alt 1", 1, mods)
modmap = modmap - 8
}
if (modmap >= 4) {
mods = gensub(/1/, "Ctrl 1", 1, mods)
modmap = modmap - 4
}
if (modmap >= 1) {
mods = gensub(/1/, "Shift 1", 1, mods)
modmap = modmap - 1
}
mods = gensub(/1/, "", 1, mods)
# output
printf "%s,%s%s,%s\n", submap, mods, $3, $4
}
'
# get binds
binds=$(hyprctl binds -j | jq -r '.[] | select(.description != "") | [.submap, .modmask, .key, .description, .dispatcher, .arg] | @tsv')
idx=$(printf "%s" "$binds" | awk -F'\t' "$awkcommand" | column -ts',' | rofi -i -dmenu -p "Keybinds" -config ~/.config/rofi/keybinds.rasi -format d)
exit
# This is permanently borked i think.
# Since hyprland0.55 (the lua update), hyprctl binds no longer provides the actual command
# Instead, a pointer to a lua fragment is printed instead, which we can't do anything with.
# exit if user does not make a selection.
if [[ $idx -eq 0 ]]; then
printf "No command selected.\nExiting..\n"
exit
fi
# get line
cmdline=$(printf "%s" "$binds" | awk -F'\t' "NR == $idx {printf \"%s %s\", \$5, \$6}")
# run hyprctl dispatch $5 $6 (< 5,6 of line not shell script)
hyprctl eval $cmdline

View File

@@ -0,0 +1,25 @@
#!/usr/bin/env bash
# This script allows the user to make a screenshot (through slurp)
# and will then open said screenshot from the clipboard into feh
# it will also make the feh window floating, and move it to the original position of the selection
slop=$(slurp -f "%x,%y %wx%h" || exit 1)
# If the capture was cancelled, out will be empty
if [[ -n "$slop" ]]; then
# get x,y of selection
coords=$(echo "$slop" | awk -F' ' '{print $1}')
x=$(echo "$coords" | awk -F',' '{print $1}')
y=$(echo "$coords" | awk -F',' '{print $2}')
grim -g "$slop" - | wl-copy
grim -g "$slop" - | feh - -T notitle --class 'floatme' &
pid="$!"
while [[ -z $(wmctrl -lp | awk -vpid=$pid '$3==pid {print $1; exit}') ]]; do
sleep 0.05
done
hyprctl dispatch "hl.dsp.window.move({ x = \"$x\", y = \"$y\", relative = false})"
fi

View File

@@ -0,0 +1,43 @@
#!/usr/bin/env bash
# This script allows toggling the active screen_shader used in hyprland.
# It automatically discovers shader files in the $SHADERDIR folder.
# And uses rofi for a graphical gui-- this uses the shaders.rasi configuration file.
# (Also dunst for notifications.)
SHADERDIR="$HOME/.config/hypr/shaders/"
function dunst() {
dunstify \
-r 2137 \
-t 2000 \
-u low \
-i ~/.icons/candy-icons/apps/scalable/applets-screenshooter.svg \
"${1/.*/}"
}
shaders="reset,
$(find "$SHADERDIR" -type f -regextype posix-extended -iregex '.*(frag|vert|glsl)$' | awk -F'[./]' '{printf "%s,%s.%s\n", $(NF-1), $(NF-1), $NF}')"
idx=$(printf "%s" "$shaders" | awk -F',' '{print $1}' | rofi -i -dmenu -P Shaders -config ~/.config/rofi/shaders.rasi -format d)
# apply selected shader (if any)
if [[ $idx -eq 0 ]]; then
printf "No shader selected.\nExiting..\n"
exit
fi
if [[ $idx -eq 1 ]]; then
# selected reset, which is a special case
hyprctl reload
dunst "Reset shader"
exit
fi
file=$(printf "%s" "$shaders" | awk -F',' "NR == $idx {printf \"%s\n\", \$2}")
hyprctl dispatch "hl.config({ decoration = { screen_shader = '$SHADERDIR/$file'}})"
dunst "Applied shader $file"

View File

@@ -0,0 +1,44 @@
#!/usr/bin/env bash
# This script allows toggling the active screen_shader used in hyprland.
# It automatically discovers shader files in the $SHADERDIR folder.
# And uses rofi for a graphical gui-- this uses the shaders.rasi configuration file.
# (Also dunst for notifications.)
SHADERDIR="$HOME/.config/hypr/windowShaders/"
function dunst() {
dunstify \
-r 2137 \
-t 2000 \
-u low \
-i ~/.icons/candy-icons/apps/scalable/applets-screenshooter.svg \
"${1/.*/}"
}
shaders="reset,
$(find "$SHADERDIR" -type f,l -regextype posix-extended -iregex '.*(frag|vert|glsl)$' | awk -F'[./]' '{printf "%s,%s.%s\n", $(NF-1), $(NF-1), $NF}')"
idx=$(printf "%s" "$shaders" | awk -F',' '{print $1}' | rofi -i -dmenu -P Shaders -config ~/.config/rofi/shaders.rasi -format d)
# apply selected shader (if any)
if [[ $idx -eq 0 ]]; then
printf "No shader selected.\nExiting..\n"
exit
fi
if [[ $idx -eq 1 ]]; then
# selected reset, which is a special case
hyprctl dispatch 'hl.dsp.window.clear_tags()'
hyprctl reload
dunst "Reset shader"
exit
fi
name=$(printf "%s" "$shaders" | awk -F',' "NR == $idx {printf \"%s\n\", \$1}")
hyprctl dispatch "hl.dsp.window.tag({ tag = 'shader/$name'})"
dunst "Applied shader $file"

View File

@@ -0,0 +1,14 @@
#!/usr/bin/env bash
# toggles focus between floating and tiled windows.
# get floating state of active window
floating=$(hyprctl activewindow -j | jq ".floating")
if [ "$floating" = "true" ]; then
# focus tiled
hyprctl dispatch "hl.dsp.window.cycle_next({ tiled = true })"
else
# focus floating
hyprctl dispatch "hl.dsp.window.cycle_next({ floating = true })"
fi

View File

@@ -0,0 +1,28 @@
#!/usr/bin/env bash
touchpad="uniw0001:00-093a:0255-touchpad"
statFile="/tmp/tpEnabled"
if [ ! -f "$statFile" ]; then
echo "false" > "$statFile"
fi
current=$(cat "$statFile")
if [[ "$current" = "true" ]]; then
newState="false"
msg="disabled"
else
newState="true"
msg="enabled"
fi
hyprctl eval "hl.device({ name = \"$touchpad\", enabled = $newState})"
echo "$newState" > "$statFile"
dunstify -u low \
-a Touchpad \
-i ~/.icons/candy-icons/apps/scalable/cs-desktop.svg \
-r 365 \
-t 1000 \
"Touchpad $msg"

16
scripts/hypr-scripts/waybar.sh Executable file
View File

@@ -0,0 +1,16 @@
#!/usr/bin/env nix-shell
#! nix-shell -i bash --packages killall envsubst waybar
#kill old instance
kill $(ps aux | grep '[w]aybar -c /tmp/waybar-config' | awk -F' ' '{print $2}')
while pgrep -u $UID -x waybar > /dev/null; do
sleep 1;
killall -q waybar
kill $(ps aux | grep '[w]aybar -c /tmp/waybar-config' | awk -F' ' '{print $2}')
done
IFS=$'\t\n'
MONITOR=$(hyprctl monitors -j | jq -r '.[] | select(.x==0 and .y==0) | .name') envsubst < ~/.config/waybar/config > /tmp/waybar-config
unset IFS
waybar -c /tmp/waybar-config &

View File

@@ -0,0 +1,66 @@
//modified version of [this shader](https://github.com/wessles/GLSL-CRT/blob/master/shader.frag)
#version 300 es
precision mediump float;
in vec2 v_texcoord;
uniform sampler2D tex;
out vec4 FragColor;
const vec3 VIB_RGB_BALANCE = vec3(1.0, 1.0, 1.0);
const float VIB_VIBRANCE = 0.40;
const vec3 VIB_coeffVibrance = VIB_RGB_BALANCE * -VIB_VIBRANCE;
void main() {
vec2 tc = vec2(v_texcoord.x, v_texcoord.y);
// Distance from the center
float dx = abs(0.5-tc.x);
float dy = abs(0.5-tc.y);
// Square it to smooth the edges
dx *= dx;
dy *= dy;
tc.x -= 0.5;
tc.x *= 1.0 + (dy * 0.05);
tc.x += 0.5;
tc.y -= 0.5;
tc.y *= 1.0 + (dx * 0.18);
tc.y += 0.5;
// Get texel, and add in scanline if need be
vec4 cta = texture(tex, vec2(tc.x, tc.y));
cta.rgb += sin(tc.y * 1250.0) * 0.02;
// Cutoff
if(tc.y > 1.0 || tc.x < 0.0 || tc.x > 1.0 || tc.y < 0.0)
cta = vec4(0.0);
// RGB
vec3 color = vec3(cta[0], cta[1], cta[2]);
// vec3 VIB_coefLuma = vec3(0.333333, 0.333334, 0.333333); // was for `if VIB_LUMA == 1`
vec3 VIB_coefLuma = vec3(0.212656, 0.715158, 0.072186); // try both and see which one looks nicer.
float luma = dot(VIB_coefLuma, color);
float max_color = max(color[0], max(color[1], color[2]));
float min_color = min(color[0], min(color[1], color[2]));
float color_saturation = max_color - min_color;
vec3 p_col = vec3(vec3(vec3(vec3(sign(VIB_coeffVibrance) * color_saturation) - 1.0) * VIB_coeffVibrance) + 1.0);
cta[0] = mix(luma, color[0], p_col[0]);
cta[1] = mix(luma, color[1], p_col[1]);
cta[2] = mix(luma, color[2], p_col[2]);
// Apply
FragColor = cta;
}

View File

@@ -0,0 +1,22 @@
// blue light filter shader
// values from https://reshade.me/forum/shader-discussion/3673-blue-light-filter-similar-to-f-lux
#version 300 es
precision mediump float;
in vec2 v_texcoord;
uniform sampler2D tex;
out vec4 FragColor;
void main() {
vec4 pixColor = texture(tex, v_texcoord);
// red
pixColor[0] *= 0.7;
// green
pixColor[1] *= 0.6;
// blue
pixColor[2] *= 0.5;
FragColor = pixColor;
}

View File

@@ -0,0 +1,18 @@
#version 300 es
precision mediump float;
in vec2 v_texcoord;
uniform sampler2D tex;
out vec4 FragColor;
// Values obtained from: http://en.wikipedia.org/wiki/Grayscale#Luma_coding_in_video_systems
vec3 LumaFactors = vec3(0.299, 0.587, 0.114);
void main() {
vec4 c = texture(tex, v_texcoord);
// Desaturate to luma only
float luma = dot(vec3(c.r, c.g, c.b), LumaFactors);
FragColor = vec4(luma, luma, luma, c.a);
}

View File

@@ -0,0 +1,31 @@
#version 300 es
precision mediump float;
in vec2 v_texcoord;
uniform sampler2D tex;
out vec4 FragColor;
uniform mediump float time;
const float display_framerate = 60.0;
const vec2 display_resolution = vec2(2520.0, 1680.0);
const float gamma = 1.0;
float rand(vec2 uv, float t) {
return fract(sin(dot(uv, vec2(1225.6548, 321.8942))) * 4251.4865 + t);
}
float Sigmoid(float x) { return 1.0 / (1.0 + (exp(-(x - 0.5) * 14.0))); }
void main() {
vec4 color = texture(tex, v_texcoord);
color = vec4(Sigmoid(color.r), Sigmoid(color.g), Sigmoid(color.b), 1.0);
color = pow(color, vec4(gamma));
color.a = 1.0;
FragColor = color;
}

View File

@@ -0,0 +1,11 @@
#version 300 es
precision mediump float;
in vec2 v_texcoord;
uniform sampler2D tex;
out vec4 FragColor;
void main() {
vec4 pixColor = texture(tex, v_texcoord);
pixColor.rgb = 1.0 - pixColor.rgb;
FragColor = pixColor;
}

View File

@@ -0,0 +1,23 @@
#version 300 es
precision mediump float;
in vec2 v_texcoord;
uniform sampler2D tex;
out vec4 FragColor;
// Values obtained from: http://en.wikipedia.org/wiki/Grayscale#Luma_coding_in_video_systems
vec3 LumaFactors = vec3(0.299, 0.587, 0.114);
void main() {
vec4 c = texture(tex, v_texcoord);
// average brightness
float luma = dot(vec3(c.r, c.g, c.b), LumaFactors);
if (c.r < c.g) {
FragColor = vec4(luma, c.g, luma, c.a);
} else {
FragColor = vec4(c.r, luma, luma, c.a);
}
// FragColor = vec4(c.r, c.g, luma, c.a);
}

View File

@@ -0,0 +1,23 @@
#version 300 es
precision mediump float;
in vec2 v_texcoord;
uniform sampler2D tex;
out vec4 FragColor;
// Values obtained from: http://en.wikipedia.org/wiki/Grayscale#Luma_coding_in_video_systems
vec3 LumaFactors = vec3(0.299, 0.587, 0.114);
void main() {
vec4 c = texture(tex, v_texcoord);
// average brightness
float luma = dot(vec3(c.r, c.g, c.b), LumaFactors);
if (c.r < c.b) {
FragColor = vec4(luma, luma, c.b, c.a);
} else {
FragColor = vec4(c.r, luma, luma, c.a);
}
// FragColor = vec4(c.r, luma, c.b, c.a);
}

View File

@@ -0,0 +1,23 @@
#version 300 es
precision mediump float;
in vec2 v_texcoord;
uniform sampler2D tex;
out vec4 FragColor;
// Values obtained from: http://en.wikipedia.org/wiki/Grayscale#Luma_coding_in_video_systems
vec3 LumaFactors = vec3(0.299, 0.587, 0.114);
void main() {
vec4 c = texture(tex, v_texcoord);
// average brightness
float luma = dot(vec3(c.r, c.g, c.b), LumaFactors);
if (c.g < c.b) {
FragColor = vec4(luma, luma, c.b, c.a);
} else {
FragColor = vec4(luma, c.g, luma, c.a);
}
// FragColor = vec4(luma, c.g, c.b, c.a);
}

View File

@@ -0,0 +1,19 @@
//modified version of [this shader](https://github.com/wessles/GLSL-CRT/blob/master/shader.frag)
#version 300 es
precision mediump float;
in vec2 v_texcoord;
uniform sampler2D tex;
out vec4 FragColor;
const float scaleFactor = 0.7;
// [0,1]
void main() {
vec4 cta = texture(tex, v_texcoord);
// cta += vec4(cos(v_texcoord.x)/4., sin(v_texcoord.y)/4., 0., 1.);
cta += vec4(cos(v_texcoord.x)/4., cos(v_texcoord.y)/8., sin(v_texcoord.y)/4., 1.);
FragColor = vec4(clamp(cta.x, 0., 1.), clamp(cta.y, 0., 1.), clamp(cta.z, 0., 1.), clamp(cta.w, 0., 1.));
}

View File

@@ -0,0 +1,14 @@
//modified version of [this shader](https://github.com/wessles/GLSL-CRT/blob/master/shader.frag)
#version 300 es
precision mediump float;
in vec2 v_texcoord;
uniform sampler2D tex;
out vec4 FragColor;
// [0,1]
void main() {
vec4 cta = texture(tex, v_texcoord);
FragColor = vec4(cta.z, cta.y, cta.x, cta.a);
}

353
scripts/mpv-visualizer.lua Executable file
View File

@@ -0,0 +1,353 @@
-- various audio visualization
local opts = {
mode = "novideo",
-- off disable visualization
-- noalbumart enable visualization when no albumart and no video
-- novideo enable visualization when no video
-- force always enable visualization
name = "showcqt",
-- off
-- showcqt
-- avectorscope
-- showspectrum
-- showcqtbar
-- showwaves
quality = "medium",
-- verylow
-- low
-- medium
-- high
-- veryhigh
height = 6,
-- [4 .. 12]
forcewindow = true,
-- true (yes) always run visualizer regardless of force-window settings
-- false (no) does not run visualizer when force-window is no
}
-- key bindings
-- cycle visualizer
local cycle_key = "c"
if not (mp.get_property("options/lavfi-complex", "") == "") then
return
end
local visualizer_name_list = {
"off",
"showcqt",
"avectorscope",
"showspectrum",
"showcqtbar",
"showwaves",
}
local axis_0 = "image/png;base64," ..
"iVBORw0KGgoAAAANSUhEUgAAB4AAAAAgCAQAAABZEK0tAAAACXBIWXMAAA7EAAAOxAGVKw4bAAASO0lEQVR42u2de2wU1xXGV/IfSJEqVUJCQrIUISFFiiqhSFWkKFKFokpB1TqxHROT8ApueDgEE9u4MW4TSqFA" ..
"3TSUQmkSChRwII6BkAQCDSYlBtc1hiSA4/CyMcYGtsZvY3t3vXu719vVPjxzz71zd+wBvnOkdvHZ78w5v7mZmbt7Z9blgsFgMBgMBoPBYDAYDAaDwWAwGAwGg8FgMBgMBoPBYDAYDAaDwWCw+9HYBFbKboe8lE1A" ..
"HHHEEUccccQRRxxxxBFHHPEHNe4KBSJWijjiiCOOOOKII4444ogjjjjiD1icwWAwGAwGg8FgMBgM9hAYJsAwGAwGg8FgMBgMBnsozOVyR7zuQOSPdQeif0UcccQRRxxxxBFHHHHEEUcc8QciHn05KaPuwGDHYEfd" ..
"gUkZRgkQRxxxxBFHHHHEEUccccQRR/w+jhu9FQ6Hw+FwOBwOh8Ph8AfOx3Zz07LTXpmYzl89McuJOJ6e/czcCWkP7u4Gf/AHf/AHf/AHf/AHf/AHf/B/iPm73D99qaW2u7n7RqI/8lz4LWbxw1tVNjQh7dgH/Z6R" ..
"JdjBzmuXKxl7b42sdvqctrORCjqvTc1S3elx9V9vOXNy1+gcP3r+5K6Bu7y8YW/jqZO7PPU5S+Tyx/Fp9lysO/CLV1TqA3/wB3/wB3/wB3/wB3/wB3/wB/8x4e9yL37N+PlYP3o+/BazePVe+c089XL7D4n6qjJZ" ..
"dUlhrO7TLWo7wKj+gbvxkGbMv3sl8T3Ht8vlL8hLVPr6dq7Xqw/8wR/8wR/8wR/8wR/8wR/8wR/8k86f/89bK26eYazjSsXGsJ8ui90Bo+MVG7ua1HZAY1VoZj9Utacof8b8DSU15cGAmn5tcfnG/zaE2+tqUtsB" ..
"8fXv33T6w8EOxpprYt9xs46xgK9qT0Hes/M2rbr13cgA2SOfP+hnrLacZ68t72sNiYNvrbBWH/iDP/iDP/iDP/iDP/iDP/iDP/jbxD/8f3UVjF2v5q8ef9HlXpQbyjAcuxY7Gp8y8uV1878ZO7lLtsDNv+Ul/e5X" ..
"0b9cqlT9JGFypq+XscZTHM3bRaq7IFo/9z+/zZivPxrdsY7Xt35l5N8paV3XGavcLp8/4GMs0t+UrFvf8mESWcKgVh/4gz/4gz/4gz/4gz/4gz/4gz/428Q/vsC1xQFf9b5JGXcvf3/UqIE1bw57az5yuff/uadl" ..
"eZ5sefzzh8ZTsX+ZPmfvO5MzVRCWv8tXhz8xi6O5+pXeDqjaw1hvazTaFNqtjV/Hvn/Xho4ruUut7QCXO/vV4DBja95Ur0+Ff+Fy8Ad/8Ad/8Ad/8Ad/8Ad/8Ad/8FfgHy2wt7Wugs+d284aNxCJ36xTbb+7mbGj" ..
"76uq4p2vYb9U6XIf3sq/LH/qZfUdwOuvq/juM89F/nnD3ndi6gvt1C+06ovfAaGMN9Q6Bn/wB3/wB3/wB3/wB3/wB3/wB3/b+UcLjFjbOeMGRPFHnpu7yBzKPQ9jkduSH39xweKcJTlLFiz+Sbas3uVe9jrf8soC" ..
"rh8eZOzETpXtx9cfvgm7IOb76/6Y+sw8Je3Jl+R3AF/TfrpMXq/LX5yf5k/VR/FX6c8K/4npOUvi61XjT+l1+Yvz0/yp+ij+Kv1Z4f/oC4tyfz7POn9Kr8tfnJ/mT9VH8Vfpz9rxR+0EMPr4Q5+g9I4/Ipc5/oid" ..
"Pv7I9wf+9yf/1MxXc/kCQav8Rfpk8DfPL8dfVJ8Mf9n+MP7vv/HPr29/Nts6f0qfjOt/8/xy1/+i+mSu/2X7szb+017JWWK+qJYe/2K9/vgX5ZcZ/+L66PEv35/Djj/RAgfaG6u6Gs0/gTCPry4aaOdtNf/70ReM" ..
"NtJ/i7GyUv6qII/ffv1/Cxbly+ld7otH+Kr469Xcvd2M9d+OXSFP60fqv8vVzdWe+oCXsYA3+hV5/23GPvyjGaKfZB/a0nTK211/VH4H3DkfGiQ75PU6/On8Yv4y9Yn4S/dnkX9KWs1HXMEXUZj9epmIv4xehz+d" ..
"X8xfpj4Rf+n+LPJPzfz+GOfLWOfVuYvU+cvodfjT+cX8ZeoT8ZfuzyL/sJcU+geHB+ctVucvo9c7/lP5qeM/XZ/4+C/Zn0X+0+cEfGEf9n77qTp/Gb0Ofzq/mL9MfSL+0v1pjP8JabUf8wsvFvzkL1bGP6XXHf/i" ..
"/PT4p+qjxr9Ufxb5tzdE9i/3jBxV/jJ6Hf50fjF/mfpE/KX7szz+95R6e3jBd86b/cCLePzTer3xT+Wnxj9dn3j8S/Znmf9rr/e08Pz9HmvnX1qvx5/KT/Gn6xPzl+xP6/pHbQI8+vpHYgLM12i/t4axugMu94aS" ..
"tm8W5cY3wON/X8fYuYOJF6D3PN7ek7svf8VYTbnRRtrOMla1m796Zm74t564+e+FPwWg9VOz/AOJj7revEp++4lr0J98qb2BsfYfIv/mzzerrTBDdO4gX/3OmPwEeELaUGeowt/K63X40/nF/Gm9mL9Kf1b4f7mN" ..
"sdvnj29vrmbBq1+r85fR6/Cn84v503oxf5X+rPCv2MhYS+2xbRePDA92XlPnL6PX4U/nF/On9WL+Kv1Z4R8m2nmNb9Xst/FE/GX0Ovzp/GL+tF7MX6U/K/yfmcsfqXG58nLlD8e3rlbnL6PX4U/nF/On9WL+Kv1Z" ..
"G/+pmfwpop3Xaj769tDqIvXxT+v1xj+Vnxr/lJ4a//L9WeHf3jDQwffu5cq+NsaM17mI+MvodfjT+cX8ab2Yv0p/Vvgvez043Nd6uqzhy4DPU69+/JHR6/Cn84v503oxf5X+rPBPSeu+4R+s3ne6zD8w0G5856yI" ..
"v4xehz+dX8yf1ov5q/Rn9fpHbQI8+vpHegLscucuTQnN7fnTvmK/5o7G85alpI2+AA3jaP5PwBt9eHfUa/kK8JsRNFOypmbxXRJ5DDetP7QltLsG+ArysPe2hi45z8hvP3EHuNzb1jLm7Y386/SHoX/1zJgfjU9M" ..
"L3931sLI7nq7aGK6ygT4c75O3v/MXHm9Dn86v5g/rRfzV+tPnX/bue7m8OdNjaeGBxO/+aH5y+h1+NP5xfxpvZi/Wn/q/KdmrS0Ovzr/GWPGP4Mu4i+j1+FP5xfzp/Vi/mr9qfPnzu+84ZdXchPgeP4yeh3+dH4x" ..
"f1ov5q/Wnzp/PsGjfjJCxF9Gr8Ofzi/mT+vF/NX6szL++c+CfHPI+MgmM/5pvd74p/JT45/SU+NfpT91/sX5kUl1b2t3szp/Gb0Ofzq/mD+tF/NX60+d/4kdjIUnQ98eYsx4kbuIv4xehz+dX8yf1ov5q/Wnzn/m" ..
"Lxk7/eFIH+WM7Vinyl9Gr8Ofzi/mT+vF/NX6s3b9ozYBHn39Q0yAfzabPxb79vmi/Ih7vo89QEfjK94YfaftuU+CgfC0k4My+hJ8xnz/YGjG31BakprJPzFYnsefJRbJT+mfnce/+G89G/ls7cmX6vYzFgwW54eH" ..
"Ar39+P7eWlGx0VPPF0xE4o/N7LvFv9bfUxr+z6cg785Fxm7GXWKJJnjTsgN+xg5uKsovzt/2+4tHWHD0CnSRXo8/nT+Rf96yWP6UnuKv2p8q/6deDt/dMTG9+8Y9jyz/aHe0Xo8/nV/Mn9JT/FX7szb+p8/ZvGqw" ..
"o7NRnT+tT8b4F+WXGf/mernxL9+fOv+nZ/v6Oq9+9Q+zCR7Fn9Lr8qfyU/zFepq/Wn+q/PkEr/1Sc03LmSPvGU8yxPxpvR5/Or+YP6Wn+Kv2p8p/UoZ/sKvx6dkbSqbPkT//RunRej3+dH4xf0pP8Vftz9rxn196" ..
"m91XJ3P8F+mTcfwX5Zc5/pvr5Y7/8v2p8t+6mrHPt05Ie2LWnfP3/qvOn9br8afzi/lTeoq/an+q/GctDH8r63Lvfcf4m0oxf1qvx5/OL+ZP6Sn+qv1ZPf6Yu9zxx3QCnLuUPzR6tEVShOLRdeMsGEicmTediszl" ..
"d65nrLTEaDOfbuFFcbm3h/9oMbfIwUKsX1v8f2XI+CdtM+aH73fkFl7wTG0/vv6IBXwlhdH3FC739ob/7usN5w8Gd/9BboI4a+Fofo1f/zhddoKqy5+egIr5i/WJ/J+dF+Vf+7Fkf0ngPymj5Qxjxz6Q4990amJ6" ..
"4mWKmT45/M3zy/E308vyF/anzX/Lav63oU6jB03I8Bfpk8FflF+Gv7lejj/Rnyb/H44Hg0X5lduNJ3g0f7Fen784P81fpJfhT/anxf+JWSMLxgYHOxJ/rEGOP6XX5U/lp/iL9TR/if60+OcuDV0sXeCXcEG/0ZM9" ..
"Kf6UXpc/lZ/iL9bT/CX6S8L51+Wu/djq8UesT8751zy/3PnXTC97/hX2p8mf32Tm7Q0O+/tXvGGFv1ivz1+cn+Yv0svwJ/vT4p+S1tfq69+/6eRufpc9fxKyGn9Kr8ufyk/xF+tp/hL9JeX4Y+ayxx/TCfC07PAt" ..
"zGY7ID7e70m8zb/pdOwE9I+/Nt5QacmdC1EQnVc/+lOkRLF+1kK+tG3k8rKLD+/JmXevhHfJ8ODx7TLbT+wvGLznaTr12uuJlxEXDocfZcOt7WxkWSM9wZuW3R3NH/T3tzfsKVWZoOryl5kAi/iL9Yn8J2Uk8lft" ..
"zwr/adn8AfDG9wmM5l9WOvo9Ir0+f1F+Gf7mejn+Kv1Z4f/YzENbQtOMQHP16AOLDH+xXp+/KL8Mf3O9HH+V/lT5/6aQBS8cdrnNJngUf1qvx5/KT/EX62n+qv2pj/+y0tKSiekpafVfMBb74C7Z8U/pdce/OD89" ..
"/kV6mfGv1p8q/02r+F+aq/f+6e6lYDD26aFy/Gm9Hn8qP8VfrKf5q/Zn7fqHP6rGeIGvzPFfrE/G9Y95frnrHzO97PWPfH+q/FMz275hbLAj4AsGyt9V50/r9fhT+Sn+Yj3NX7U/9fFflD/QMfLX0DVWzT718U/p" ..
"dce/OD89/kV6mfGv1p/V44+Zyx5/TCfAuv7NoeBw+AHYfAnygsXm73xs5sqCzauK8uO/xpfX626f8tTMksLNqwryjB6QT00wKdfVJyO/MX/n9GfGf/ZCftdBVZnVvLr6ZOU34++U/kTjn/snf9F7Wp+uXje/aPw7" ..
"oT9j/vyjjb62riZ+kmk7a/yMA5Hr6pOX35i/c/qjxn9BHmOf/dV6fl29bn5q/I93f8b8V7zBHzLHX5UUMnZyl2pWXX3y8hvzd05/ovFflK93htHVJyO/aPw7oT9j/l+8z9i2tSlpU7MaqwL+KVmqWXX1yctvzN85" ..
"/ZmP/ylZ61fmLj25m2/JSmZdfXLym49/Z/RHnX9tcf0U+zcxtvEt/up6dcCnfgEy3no5fxAmwPdnf+uKfb1BP/9s76mX/75u7PVOr8/u/qK+Yx1j5p/x2q93en329Hf5q86r3PlPvd08o35809U7vT67+5ucGbnX" ..
"74M1jO3aMNZ6p9dnd39TsoaHum/wVzlLGPvXP8Za7/T67O4v7GcPitZ32K93en329dfwZdCfOvIAoyN/Y8xskbF9eqfXZ3d/EV/zZsDXdV30qDl79U6vz+7+bPJknAAG2oe6jm///hhjdfvvPz3lxfkXDtcfZay7" ..
"pf5obYX02vKk6Z1en739PTuP37PQ1VR/tP6o5yJjks92S5re6fXZ3Z/L3VzdXP351oObqvcNdfv6jX/mwU690+uzu7+wn9jZfinysInx0Du9Pvv662rsaancvn9TzT5vz1D3tOyx1ju9Prv7c7n5mb3hn59u6bjC" ..
"TJcY26l3en1298f9nqf7+njqnV6fff2Vv8t/4urEzu8+8/V7e1Izx1rv9Prs7u/xF2srTuy4+q9gYKizcPnY651en9392ezJSLJ+5VAXX4DdenZq1v2oF3vl9uhN1v7+2Id1j43e6fXZ29/shfF3RryQM7Z6p9dn" ..
"d38ud/W+yL0Zva3rV4693un12d0f9x+n8x+zZ+yeZ1LGeOidXp+d/ZVv9PaE9293i9kdtnbqnV6f3f3x59u3/Cf84JQv3h8PvdPrs7s/l/uR5/pu6Sxu19U7vT57+6v9OHyG6WuL/tTLWOqdXp+9/WXk8AfMMea5" ..
"+ItXxkPv9Prs7s9mT9YpIHepTvvjrYfD4Waempm7tDj/+QVWl7fo6p1en939wcfXH3luweKifLMfmbFf7/T67O6Pe/ary/MefWH89E6vz+7+4OPpU7Pyls38pfXzi67e6fXZ29/kzOV5OrMLXb3T67O7P1sdBxc4" ..
"HA6Hw+FwOBwOhz8UDgRwOBwOh8PhcDgcDn8oHAjgcDgcDofD4XA4HP4w+P8AQEuXMXpD8/kAAAAASUVORK5CYII="
local axis_1 = "image/png;base64," ..
"iVBORw0KGgoAAAANSUhEUgAAB4AAAAAwCAQAAABaxq+2AAAACXBIWXMAAA7EAAAOxAGVKw4bAAATVklEQVR42u2df0xUZ7rHJ+EPkiabbGJiYkLSmJg0aTYxTTZNmiYb09ykZjO0QLHY+quy9Qe1YgG5Re62rlev" ..
"etluXVevt62rrkq1FLG21epW7FqUZRFtq1LqLxAR1FnkNwIzw8x752V27gzDOe/zvuedA0f5fp9kd+SZ7zPv8zlvz5x35pwzLhcEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAE" ..
"QRAEQRAEQRAEQRAEQRAEQRAEQRBkq1gyK2F3Q1HCkpFHHnnkkUceeeSRRx555JFH/lHNu0KJiEqQRx555JFHHnnkkUceeeSRR/4RyzMIgiAIgiAIgiAImgTCAhiCIAiCIAiCIAiaFHK53JGoq4j8sa4i+lfkkUce" ..
"eeSRRx555JFHHnnkkX8k8tGHU9PrKgY7BjvqKqamGxVAHnnkkUceeeSRRx555JFHHvmHOG/0VAQCgUAgEAgEAoFAIB65AAIEAoFAIBAIBAKBQEyKAAIEAoFAIBAIBAKBQEyKGN+Xm5mV+tqUNP7oqblOxPHsvOcW" ..
"JKc+upsb/MEf/MEf/MEf/MEf/MEf/MF/EvN3uX/5Skttd3P3rfh47IXwU8zyR3eovFBy6omP+j0jN+EKdt64WsnYB+tlvbPmt52PjKDzxoxM1Y0+avw3W86d3ju2xs9ePL134D4f3rC38czpvZ767OVy9UfxafZc" ..
"rqv49Wsq4wN/8Ad/8Ad/8Ad/8Ad/8Ad/8Af/ceHvci97w/gXkn72YvgpZvnqA/Iv88yr7T/F+6tKZd3FBbG+z7erbQCj8Q/cHw1p9qL71+Kfc3KXXP383Hinr2/PJr3xgT/4gz/4gz/4gz/4gz/4gz/4g3/C+fP/" ..
"eWf17XOMdVwr3xKOs6WxG2BsvnxLV5PaBmisCq3sh6r2F+bNXrS5uKYsGFDzbygq2/LPhnB7XU1qG2D0+A9tPfvxYAdjzTWxz7hdx1jAV7U/P/f5hVvX3vlhZILsl68f9DNWW8ar15b1tYbMwXdWWxsf+IM/+IM/" ..
"+IM/+IM/+IM/+IM/+NvEP/x/deWM3azmj5582eVemhOqMBx7LnY0P33ky+vmvzN2eq/sALf9jg/pP/89+pcrlaqfJEzL8PUy1niGo3m3UHUTRMfP44/vMubrj2Z3b+Tj27Qm8u+k1K6bjFXukq8f8DEW6W965p3v" ..
"+TSJnMKgNj7wB3/wB3/wB3/wB3/wB3/wB3/wt4n/6AFuKAr4qg9OTb9/9cfjRg2sf3vYW/OJy33ojz0tq3Jlh8c/f2g8E/uXWfMPvDctQwVh2fv87PCn5nI017/R2wBV+xnrbY1mm0KbtfHb2Ofv3dxxLWeFtQ3g" ..
"cme9HhxmbP3b6uNT4V+wCvzBH/zBH/zBH/zBH/zBH/zBH/wV+EcH2NtaV87Xzm3njRuI5G/Xqbbf3czY8Q9VXaODn8N+pdLlPrqDf1n+zKvqG4CPv678hy88l/nnDQfeixlfaKN+pTW+0RsgVPGWWsfgD/7gD/7g" ..
"D/7gD/7gD/7gD/7gbzv/6AAjartg3IAo/9gLC5aaQ3ngYSxyWfKTLy9elr08e/niZb/IkvW73Cvf5K+8Jp/7hwcZO7VH5fVHjz98EXZ+zPfX/THjM4uk1Kdfkd8A/Jz2s6Xyfl3+4vo0f2p8FH+V/qzwn5KWvXz0" ..
"eNX4U35d/uL6NH9qfBR/lf6s8H/8paU5/7bQOn/Kr8tfXJ/mT42P4q/Sn7X9j9obwNj9D/0Gpbf/EYXM/kcc9P5Hvj/wfzj5p2S8nsNPELTKX+RPBH/z+nL8ReOT4S/bH+b/wzf/+fHtr+ZZ50/5E3H8b15f7vhf" ..
"ND6Z43/Z/qzN/9TXspebn1RLz3+xX3/+i+rLzH/x+Oj5L9+fw/Y/0QEOtDdWdTWafwJhnl9XONDO22r+++MvGb1I/x3GSkv4o/xcfvn1vxQszJPzu9yXj/Gz4m9W8/B2M9Z/N/YMedo/Mv773N1c7akPeBkLeKNf" ..
"kfffZezj35sh+kXWke1NZ7zd9cflN8C9i6FJslver8Ofri/mLzM+EX/p/izyT0qt+YQ7+EkUZr9eJuIv49fhT9cX85cZn4i/dH8W+adk/HiC82Ws8/qCper8Zfw6/On6Yv4y4xPxl+7PIv9wFBf4B4cHFy5T5y/j" ..
"19v/U/Wp/T89PvH+X7I/i/xnzQ/4wjHs/f5zdf4yfh3+dH0xf5nxifhL96cx/5NTaz/lB14s+NmfrMx/yq87/8X16flPjY+a/1L9WeTf3hDZvjzSs1X5y/h1+NP1xfxlxifiL92f5fm/v8Tbwwd876LZD7yI5z/t" ..
"15v/VH1q/tPjE89/yf4s83/jzZ4WXr/fY+39l/br8afqU/zp8Yn5S/andfyjtgAee/wjsQDm52h/sJ6xugqXe3Nx23dLc0Y3wPN/3sjYhcPxB6APPN7e0/uufsNYTZnRi7SdZ6xqH3/03ILwbz1x+R+EPwWg/TMy" ..
"/QPxt7retlb+9ePPQX/6lfYGxtp/ivyb39+sttwM0YXD/Ox3xuQXwMmpQ52hEf5O3q/Dn64v5k/7xfxV+rPC/+udjN29eHJXczULXv9Wnb+MX4c/XV/Mn/aL+av0Z4V/+RbGWmpP7Lx8bHiw84Y6fxm/Dn+6vpg/" ..
"7RfzV+nPCv8w0c4b/FXNfhtPxF/Gr8Ofri/mT/vF/FX6s8L/uQX8lhpXK69W/nRyxzp1/jJ+Hf50fTF/2i/mr9KftfmfksHvItp5o+aT74+sK1Sf/7Rfb/5T9an5T/mp+S/fnxX+7Q0DHXzrXq3sa2PM+DwXEX8Z" ..
"vw5/ur6YP+0X81fpzwr/lW8Gh/taz5Y2fB3weerV9z8yfh3+dH0xf9ov5q/SnxX+Sandt/yD1QfPlvoHBtqNr5wV8Zfx6/Cn64v5034xf5X+rB7/qC2Axx7/SC+AXe6cFUmhtT2/21fs19zRfO7KpNSxB6BhHM3/" ..
"CHijN++ORi0/A/x2BM30zBmZfJNEbsNN+49sD22uAX4GeTh6W0OHnOfkXz9+A7jcOzcw5u2N/Ovsx6F/9cxeFM1PSSt7f+6SyOZ6t3BKmsoC+Et+nrz/uQXyfh3+dH0xf9ov5q/Wnzr/tgvdzeHPmxrPDA/Gf/ND" ..
"85fx6/Cn64v5034xf7X+1PnPyNxQFH508QvGjH8GXcRfxq/Dn64v5k/7xfzV+lPnz4NfecMPr+QWwKP5y/h1+NP1xfxpv5i/Wn/q/PkCj/rJCBF/Gb8Of7q+mD/tF/NX68/K/Oc/C/LdEeM9m8z8p/1685+qT81/" ..
"yk/Nf5X+1PkX5UUW1b2t3c3q/GX8Ovzp+mL+tF/MX60/df6ndjMWXgx9f4Qx45PcRfxl/Dr86fpi/rRfzF+tP3X+c37D2NmPR/ooY2z3RlX+Mn4d/nR9MX/aL+av1p+14x+1BfDY4x9iAfyrefy22HcvFuZFwvNj" ..
"7A46ml/91tgrbS98FgyEl50clNGX4LMX+QdDK/6GkuKUDP6Jwapcfi+xSH3K//xC/sV/6/nIZ2tPv1J3iLFgsCgvPBXo1x/d3zury7d46vkJE5H8E3P67vCv9feXhP/zyc+9d5mx26MOsUQLvJlZAT9jh7cW5hXl" ..
"7fyvy8dYcOwZ6CK/Hn+6fjz/3JWx/Ck/xV+1P1X+z7wavrpjSlr3rQceWf7R7mi/Hn+6vpg/5af4q/Znbf7Pmr9t7WBHZ6M6f9qfiPkvqi8z/839cvNfvj91/s/O8/V1Xv/mL2YLPIo/5dflT9Wn+Iv9NH+1/lT5" ..
"8wVe+5XmmpZzxz4wXmSI+dN+Pf50fTF/yk/xV+1Plf/UdP9gV+Oz8zYXz5ov//4bpUf79fjT9cX8KT/FX7U/a/t/fuhtdl2dzP5f5E/E/l9UX2b/b+6X2//L96fKf8c6xr7ckZz61Nx7Fx/8U50/7dfjT9cX86f8" ..
"FH/V/lT5z10S/lbW5T7wnvE3lWL+tF+PP11fzJ/yU/xV+7O6/zEPuf2P6QI4ZwW/afRYRUqE8tHzxlkwEL8ybzoTWcvv2cRYSbHRy3y+nQ+K2709/EeLuSI7C7F/Q9G/nCHxT9pmLwpf78gVPuGZev3R448o4Csu" ..
"iD6nYJW3N/x3X2+4fjC477/lFohzl4zl1/jtz9NkF6i6/OkFqJi/2B/P//mFUf61n0r2lwD+U9NbzjF24iM5/k1npqTFH6aY+RPD37y+HH8zvyx/YX/a/Lev438b6jS60YQMf5E/EfxF9WX4m/vl+BP9afL/6WQw" ..
"WJhXuct4gUfzF/v1+Yvr0/xFfhn+ZH9a/J+aO3LC2OBgR/yPNcjxp/y6/Kn6FH+xn+Yv0Z8W/5wVoYOlS/wQLug3urMnxZ/y6/Kn6lP8xX6av0R/CXj/dblrP7W6/xH7E/P+a15f7v3XzC/7/ivsT5M/v8jM2xsc" ..
"9vevfssKf7Ffn7+4Ps1f5JfhT/anxT8pta/V139o6+l9/Cp7fidkNf6UX5c/VZ/iL/bT/CX6S8j+xyxk9z+mC+CZWeFLmM02wOh8vyf+Mv+ms7EL0N//h/ELlRTfuxQF0Xn9kz9Ehij2z13CT20bObzs4tN7Wsb9" ..
"a+FNMjx4cpfM68f3Fww+8DSdeePN+MOIS0fDt7LhajsfOa2RXuDNzOqO1g/6+9sb9peoLFB1+cssgEX8xf54/lPT4/mr9meF/8wsfgN44+sExvIvLRn7HJFfn7+ovgx/c78cf5X+rPB/Ys6R7aFlRqC5euyORYa/" ..
"2K/PX1Rfhr+5X46/Sn+q/H9bwIKXjrrcZgs8ij/t1+NP1af4i/00f9X+1Od/aUlJ8ZS0pNT6rxiLvXGX7Pyn/LrzX1yfnv8iv8z8V+tPlf/WtfwvzdUH/nD/SjAYe/dQOf60X48/VZ/iL/bT/FX7s3b8w29VY3yC" ..
"r8z+X+xPxPGPeX254x8zv+zxj3x/qvxTMtq+Y2ywI+ALBsreV+dP+/X4U/Up/mI/zV+1P/X5X5g30DHy19AxVs1B9flP+XXnv7g+Pf9Ffpn5r9af1f2PWcjuf0wXwLrx3ZHgcPgG2PwU5MXLzJ/5xJw1+dvWFuaN" ..
"/hpf3q/7+lSkZBQXbFubn2t0g3xqgUmFrj8R9Y35O6c/M/7zlvCrDqpKrdbV9Seqvhl/p/Qnmv88PvuT3t36dP269UXz3wn9GfPnH230tXU18TeZtvPG9zgQha4/cfWN+TunP2r+5+cy9sX/WK+v69etT83/ie7P" ..
"mP/qt/hN5vij4gLGTu9VrarrT1x9Y/7O6U80/wvz9N5hdP2JqC+a/07oz5j/Vx8ytnNDUuqMzMaqgH96pmpVXX/i6hvzd05/5vN/euamNTkrTu/jr2Slsq4/MfXN578z+qPef20J/RKHtjK25R3+6GZ1wKd+ADLR" ..
"frl4FBbAD2d/G4t8vUE//2zvmVf/vHH8/U4fn939RWP3RsbMP+O13+/08dnT39VvOq/z4D/1dvuc+v5N1+/08dnd37SMyLV+H61nbO/m8fY7fXx29zc9c3io+xZ/lL2csb/9Zbz9Th+f3f2F4/xh0fkd9vudPj77" ..
"+mv4OuhPGbmB0bH/ZczsJGP7/E4fn939RWL92wFf103Rrebs9Tt9fHb3Z1Mk4g1goH2o6+SuH08wVnfo4fNTUZR36Wj9cca6W+qP15ZLn1ueML/Tx2dvf88v5NcsdDXVH68/7rnMmOS93RLmd/r47O7P5W6ubq7+" ..
"csfhrdUHh7p9/cY/82Cn3+njs7u/cJza034lcrOJifA7fXz29dfV2NNSuevQ1pqD3p6h7plZ4+13+vjs7s/l5u/sDX/9fHvHNWZ6irGdfqePz+7+eDzwdN+cSL/Tx2dff2Xv85+4OrXnhy98/d6elIzx9jt9fHb3" ..
"9+TLteWndl//WzAw1Fmwavz9Th+f3f3ZHIkosmnNUBc/Abv1/IzMh9Evjspd0Yus/f2xN+seH7/Tx2dvf/OWjL4y4qXs8fU7fXx29+dyVx+MXJvR27ppzfj7nT4+u/vj8fM0/mP2jD3wTE2fCL/Tx2dnf2VbvD3h" ..
"7dvdYnaFrZ1+p4/P7v74/e1b/hG+ccpXH06E3+njs7s/l/uxF/ru6Jzcrut3+vjs7a/20/A7TF9b9KdextPv9PHZ2196Nr/BHGOey79+bSL8Th+f3f3ZHIl6C8hZodP+RPsRCIRZpGTkrCjKe3Gx1dNbdP1OH5/d" ..
"/SEmNh57YfGywjyzH5mx3+/08dndH4+s11flPv7SxPmdPj67+0NMZMzIzF055zfW3190/U4fn739TctYlauzutD1O318dvdna2DngkAgEAgEAoFAIBCISRFAgEAgEAgEAoFAIBCISRHRh1PT6yqGOoc66yqMr6NC" ..
"HnnkkUceeeSRRx555JFHHvmHOB99WFcRuZGO8b00kUceeeSRRx555JFHHnnkkUf+Ic4zCIIgCIIgCIIgCJoEwgIYgiAIgiAIgiAImhRyRcVK/v+vJS4DIY888sgjjzzyyCOPPPLII4/8o5B3seTQU+6EooQlI488" ..
"8sgjjzzyyCOPPPLII4/8o5qHIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCEqf/A/SNfayCCBqGAAAAAElFTkSuQmCC"
local options = require 'mp.options'
local msg = require 'mp.msg'
options.read_options(opts)
opts.height = math.min(12, math.max(4, opts.height))
opts.height = math.floor(opts.height)
if not opts.forcewindow and mp.get_property('force-window') == "no" then
return
end
local function get_visualizer(name, quality, vtrack)
local w, h, fps
if quality == "verylow" then
w = 640
fps = 30
elseif quality == "low" then
w = 960
fps = 30
elseif quality == "medium" then
w = 1280
fps = 60
elseif quality == "high" then
w = 1920
fps = 60
elseif quality == "veryhigh" then
w = 2560
fps = 60
else
msg.log("error", "invalid quality")
return ""
end
h = w * opts.height / 16
if name == "showcqt" then
local count = math.ceil(w * 180 / 1920 / fps)
return "[aid1] asplit [ao]," ..
"aformat = channel_layouts = stereo," ..
"firequalizer =" ..
"gain = '1.4884e8 * f*f*f / (f*f + 424.36) / (f*f + 1.4884e8) / sqrt(f*f + 25122.25)':" ..
"scale = linlin:" ..
"wfunc = tukey:" ..
"zero_phase = on:" ..
"fft2 = on," ..
"showcqt =" ..
"fps =" .. fps .. ":" ..
"size =" .. w .. "x" .. h .. ":" ..
"count =" .. count .. ":" ..
"csp = bt709:" ..
"bar_g = 2:" ..
"sono_g = 4:" ..
"bar_v = 9:" ..
"sono_v = 17:" ..
"axisfile = data\\\\:'" .. axis_0 .. "':" ..
"font = 'Nimbus Mono L,Courier New,mono|bold':" ..
"fontcolor = 'st(0, (midi(f)-53.5)/12); st(1, 0.5 - 0.5 * cos(PI*ld(0))); r(1-ld(1)) + b(ld(1))':" ..
"tc = 0.33:" ..
"attack = 0.033:" ..
"tlength = 'st(0,0.17); 384*tc / (384 / ld(0) + tc*f /(1-ld(0))) + 384*tc / (tc*f / ld(0) + 384 /(1-ld(0)))'," ..
"format = yuv420p [vo]"
elseif name == "avectorscope" then
return "[aid1] asplit [ao]," ..
"aformat =" ..
"sample_rates = 192000," ..
"avectorscope =" ..
"size =" .. w .. "x" .. h .. ":" ..
"r =" .. fps .. "," ..
"format = rgb0 [vo]"
elseif name == "showspectrum" then
return "[aid1] asplit [ao]," ..
"showspectrum =" ..
"size =" .. w .. "x" .. h .. ":" ..
"win_func = blackman [vo]"
elseif name == "showcqtbar" then
local axis_h = math.ceil(w * 12 / 1920) * 4
return "[aid1] asplit [ao]," ..
"aformat = channel_layouts = stereo," ..
"firequalizer =" ..
"gain = '1.4884e8 * f*f*f / (f*f + 424.36) / (f*f + 1.4884e8) / sqrt(f*f + 25122.25)':" ..
"scale = linlin:" ..
"wfunc = tukey:" ..
"zero_phase = on:" ..
"fft2 = on," ..
"showcqt =" ..
"fps =" .. fps .. ":" ..
"size =" .. w .. "x" .. (h + axis_h)/2 .. ":" ..
"count = 1:" ..
"csp = bt709:" ..
"bar_g = 2:" ..
"sono_g = 4:" ..
"bar_v = 9:" ..
"sono_v = 17:" ..
"sono_h = 0:" ..
"axisfile = data\\\\:'" .. axis_1 .. "':" ..
"axis_h =" .. axis_h .. ":" ..
"font = 'Nimbus Mono L,Courier New,mono|bold':" ..
"fontcolor = 'st(0, (midi(f)-53.5)/12); st(1, 0.5 - 0.5 * cos(PI*ld(0))); r(1-ld(1)) + b(ld(1))':" ..
"tc = 0.33:" ..
"attack = 0.033:" ..
"tlength = 'st(0,0.17); 384*tc / (384 / ld(0) + tc*f /(1-ld(0))) + 384*tc / (tc*f / ld(0) + 384 /(1-ld(0)))'," ..
"format = yuv420p," ..
"split [v0]," ..
"crop =" ..
"h =" .. (h - axis_h)/2 .. ":" ..
"y = 0," ..
"vflip [v1];" ..
"[v0][v1] vstack [vo]"
elseif name == "showwaves" then
return "[aid1] asplit [ao]," ..
"showwaves =" ..
"size =" .. w .. "x" .. h .. ":" ..
"r =" .. fps .. ":" ..
"mode = p2p," ..
"format = rgb0 [vo]"
elseif name == "off" then
local hasvideo = false
for id, track in ipairs(mp.get_property_native("track-list")) do
if track.type == "video" then
hasvideo = true
break
end
end
if hasvideo then
return "[aid1] asetpts=PTS [ao]; [vid1] setpts=PTS [vo]"
else
return "[aid1] asetpts=PTS [ao];" ..
"color =" ..
"c = Black:" ..
"s =" .. w .. "x" .. h .. "," ..
"format = yuv420p [vo]"
end
end
msg.log("error", "invalid visualizer name")
return ""
end
local function select_visualizer(vtrack, atrack)
if atrack == nil or opts.mode == "off" then
return ""
elseif opts.mode == "force" then
return get_visualizer(opts.name, opts.quality, vtrack)
elseif opts.mode == "noalbumart" then
if vtrack == nil then
return get_visualizer(opts.name, opts.quality, vtrack)
end
return ""
elseif opts.mode == "novideo" then
if vtrack == nil or vtrack.albumart then
return get_visualizer(opts.name, opts.quality, vtrack)
end
return ""
end
msg.log("error", "invalid mode")
return ""
end
local function visualizer_hook()
local count = mp.get_property_number("track-list/count", -1)
if count <= 0 then
return
end
local atrack = mp.get_property_native("current-tracks/audio")
local vtrack = mp.get_property_native("current-tracks/video")
--no tracks selected (yet)
if atrack == nil and vtrack == nil then
for id, track in ipairs(mp.get_property_native("track-list")) do
if track.type == "video" and (vtrack == nil or vtrack.albumart == true) and mp.get_property("vid") ~= "no" then
vtrack = track
elseif track.type == "audio" then
atrack = track
end
end
end
local lavfi = select_visualizer(vtrack, atrack)
--prevent endless loop
if lavfi ~= "" and lavfi ~= mp.get_property("lavfi-complex", "") then
mp.set_property("file-local-options/lavfi-complex", lavfi)
end
end
mp.add_hook("on_preloaded", 50, visualizer_hook)
mp.observe_property("current-tracks/audio", "native", visualizer_hook)
mp.observe_property("current-tracks/video", "native", visualizer_hook)
local function cycle_visualizer()
local i, index = 1
for i = 1, #visualizer_name_list do
if (visualizer_name_list[i] == opts.name) then
index = i + 1
if index > #visualizer_name_list then
index = 1
end
break
end
end
opts.name = visualizer_name_list[index]
visualizer_hook()
end
mp.add_key_binding(cycle_key, "cycle-visualizer", cycle_visualizer)

View File

@@ -0,0 +1,42 @@
#!/bin/bash
on_exit() {
(ccrypt -K "$now" -d "$file.cpt")
# prepare regex pattern
shopt -s extglob
readarray -t removeArray < <(grep -ve '^$\|^#' "$file")
IFS='|' eval 'PATTERN="(${removeArray[*]})"'
PATTERN="(^|[^a-zA-Z])$PATTERN([^a-zA-Z]|$)"
case $shell in
*fish)
printf "sanitizing fish history!\n"
"$(dirname "$0")/sanitize_hist.fish" "$PATTERN" "/home/$(whoami)/.local/share/fish/fish_history"
;;
*bash)
printf "sanitizing bash history!\n"
"$(dirname "$0")/sanitize.sh" "$PATTERN" "/home/$(whoami)/.bash_history" 1
;;
*)
printf "autosanitize has no implementation for %s\n" "$shell"
;;
esac
rm -r ~/.cache/thumbnails/*
rm "$file"
}
trap 'on_exit' EXIT
now=$(date +%s.%N)
folder=/run/media/$(whoami)/P/Scripts
file=/tmp/tags
shell=$(grep "$(whoami)" < /etc/passwd | awk -F':' '{print $NF}' )
echo "copying tags to temp file..."
cat "$folder/tags2" "$folder/tags" > "$file"
(sed -i '/^$/d;/^\#.*$/d' "$file")
(ccrypt -K "$now" "$file")
while :; do
sleep 600
done

41
scripts/sanitize/sanitize.sh Executable file
View File

@@ -0,0 +1,41 @@
#!/bin/bash
#This script sanitizes a file in the following manner:
#it reads a pattern and a destFile
#then, all lines in destFILE that can be regexp'd to pattern are removed.
#optionally, a confirm variable is also specified; if so, the script does not prompt the user before overwriting destFILE
#this script takes the following input:
#sanitize.sh pattern destFile [confirm]
#make sure input is valid
[[ "$1" == "" || "$2" == "" ]] && printf "Incorrect input format.\nUse: \t sanitize.sh pattern destFile [confirm]\n" && exit
[[ ! -f "$2" ]] && printf 'destFile - %s - does not exist!\n' "$2" && exit
PATTERN=$1
destFile=$2
saveArray=()
discardArray=()
[[ "$3" =~ [yY][eE][sS]|[yY]|1|[tT][rR][uU][eE] ]] && confirm=0 || confirm=1
#go through each line, adding to either SAVE or DISCARD as necessary
while read -r line; do
[[ ! $line =~ $PATTERN ]] && saveArray+=("$line") || discardArray+=("$line")
done < "$destFile"
#confirm output
if [[ $confirm -eq 1 ]]; then
printf "Discarding the following:\n"
printf '%s\n' "${discardArray[@]}"
else
printf 'Discarding %d line(s).\n' "${#discardArray[@]}"
fi
#confirm the user is ok with this
response="y"
[[ $confirm -eq 1 ]] && read -r -p "Proceed? (y/N): " response
if [[ "$response" =~ [yY][eE][sS]|[yY] ]]; then
echo "Removing unwanted lines..."
printf '%s\n' "${saveArray[@]}" > "$destFile"
fi

View File

@@ -0,0 +1,53 @@
#!/usr/bin/env fish
# This script filters a file on a given regex, deleting all entries that match.
# it is intended to be used with yaml-like files (namely, the fish shell history file)
# and will delete entries, not individual lines. To give an example:
# - cmd: "cd ~/Documents"
# when: 128301283
# - paths:
# /usr/bin
# - cmd: "mv file file2"
# when: 1928321
# with the regex "(^|[^a-z])(Documents)($|[^a-z])" will result in:
# - cmd: "mv file file2"
# when: 1928321
# (note how it deletes not only the line containing the matched regex, but also the 'when' and 'paths' components).
#
# the input for this script is:
# script.fish Regex File
# where:
# Regex is the pattern to be matched, and
# File is the file to be filtered.
# error handling
if not test -f "$argv[2]"
printf 'Wrong syntax!\nUse:\t%s\tRegex\tFile' "$(basename (status -f))"
exit
end
# setup
set -f is_writing "false"
set -f tempFile (mktemp -p '' fish_hist.XXXXX)
set -f num_deleted 0
# loop through the file
while read -lad ' ' line
if string match -qri "^- cmd:" -- "$line"
if string match -qri "$argv[1]" -- "$line"
set is_writing "false"
set num_deleted (math $num_deleted + 1)
else
printf '%s\n' "$line" >> "$tempFile"
set is_writing "true"
end
else if string match -q "true" -- "$is_writing"
printf '%s\n' "$line" >> "$tempFile"
end
end < "$argv[2]"
printf 'Discarding %d line(s).\n ' "$num_deleted"
# replace files
rm "$argv[2]"
cp "$tempFile" "$argv[2]"