summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xalarm11
-rwxr-xr-xbacklight23
-rwxr-xr-xbell7
-rwxr-xr-xccgsl7
-rwxr-xr-xcfg29
-rwxr-xr-xchmodef6
-rwxr-xr-xcurlqb27
-rwxr-xr-xdateft29
-rwxr-xr-xdirnameall19
-rwxr-xr-xgita17
-rwxr-xr-xgitfork10
-rwxr-xr-xgitmetap17
-rwxr-xr-xgitmetar7
-rwxr-xr-xgitpu19
-rwxr-xr-xgrrc4
-rwxr-xr-xil6
-rwxr-xr-xlastarg5
-rwxr-xr-xloop15
-rwxr-xr-xlsp3
-rwxr-xr-xmll6
-rwxr-xr-xmmi27
-rwxr-xr-xmpra44
-rwxr-xr-xmpva17
-rwxr-xr-xmpvy44
-rwxr-xr-xmvln27
-rwxr-xr-xmvtr11
-rwxr-xr-xmvtu13
-rwxr-xr-xnews31
-rwxr-xr-xo27
-rwxr-xr-xorgext18
-rwxr-xr-xpa8
-rwxr-xr-xpq13
-rwxr-xr-xpx10
-rwxr-xr-xqg15
-rwxr-xr-xqw16
-rwxr-xr-xrate11
-rwxr-xr-xreco28
-rwxr-xr-xrfp11
-rwxr-xr-xsbar77
-rwxr-xr-xta5
-rwxr-xr-xtime-uuid6
-rwxr-xr-xtopa8
-rwxr-xr-xvinfo4
-rwxr-xr-xwh11
-rwxr-xr-xwtr43
-rwxr-xr-xxmq3
46 files changed, 795 insertions, 0 deletions
diff --git a/alarm b/alarm
new file mode 100755
index 0000000..5342e7d
--- /dev/null
+++ b/alarm
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+min="$1"
+[ "$1" ] && shift
+printf "notify-send -u critical %s; bell" "$(/usr/bin/printf '%q ' "${@:-alarm}")" | at now + "${min:-0}" minutes && [ "$min" ] && [ "$min" -ne 0 ] && notify-send "Successfully Scheduled"
+
+# at used to not like string like 'Boiling Water!', don't know why now it works, if see similar issue, use folllowing codes
+#at now + "$1" minutes << EOF && notify-send 'Successfully Scheduled'
+#notify-send -u critical "${2:-alarm}"
+#bell
+#EOF
diff --git a/backlight b/backlight
new file mode 100755
index 0000000..3de87f5
--- /dev/null
+++ b/backlight
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+brightness=$(cat /sys/class/backlight/intel_backlight/brightness)
+max_brightness=$(cat /sys/class/backlight/intel_backlight/max_brightness)
+step=$((max_brightness/20))
+
+case "$1" in
+ '-u')
+ case "$brightness" in
+ 0) echo 1;;
+ 1) echo "$step";;
+ *) echo "$((brightness+step))";;
+ esac
+ ;;
+ '-d')
+ case "$brightness" in
+ 1) echo 0;;
+ "$step") echo 1;;
+ *) echo "$((brightness-step))";;
+ esac
+ ;;
+ *) exit 1;;
+esac > /sys/class/backlight/intel_backlight/brightness
diff --git a/bell b/bell
new file mode 100755
index 0000000..a0395ac
--- /dev/null
+++ b/bell
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+bef="$(amixer get Master | awk -F '[][]' 'END{print $2}')"
+amixer set Master 10%
+# code steal from https://unix.stackexchange.com/a/163716/459013
+speaker-test -t sine -f 1000 -l 1
+amixer set Master "$bef"
diff --git a/ccgsl b/ccgsl
new file mode 100755
index 0000000..31bd325
--- /dev/null
+++ b/ccgsl
@@ -0,0 +1,7 @@
+#!/bin/sh
+# steal codes from https://github.com/LukeSmithxyz/voidrice/blob/master/.local/bin/compiler
+
+base="${1%.*}"
+# -lm link math library? needed for sqrt(). not sure
+# https://stackoverflow.com/questions/44175151/what-is-the-meaning-of-lm-in-gcc
+cc -Wall -lgsl -lgslcblas -lm -o "$base" "$1" && ./"$base"
diff --git a/cfg b/cfg
new file mode 100755
index 0000000..92a097e
--- /dev/null
+++ b/cfg
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+umask 077
+while getopts lsmM opt; do
+ case $opt in
+ #c)
+ # work_tree_dir="$HOME"
+ # meta_file="$XDG_CONFIG_HOME/myconf/cfg${opt}_meta"
+ # cmd="git --git-dir=$HOME/.cfg$opt/ --work-tree=$HOME"
+ # ;;
+ l|s)
+ work_tree_dir=/
+ meta_file="/etc/myconf/cfg${opt}_meta"
+ cmd="sudo -E git --git-dir=/etc/.cfg$opt/ --work-tree=/"
+ ;;
+ m)
+ sudo gitmetap "$cmd" "$work_tree_dir" "$meta_file"
+ $cmd diff
+ exit
+ ;;
+ M)
+ sudo gitmetar "$meta_file"
+ exit
+ ;;
+ \?) exit 1;;
+ esac
+done
+shift $((OPTIND-1))
+$cmd "$@"
diff --git a/chmodef b/chmodef
new file mode 100755
index 0000000..446bc23
--- /dev/null
+++ b/chmodef
@@ -0,0 +1,6 @@
+#!/bin/sh
+# chmodef: CHMOD DEFault
+
+# https://wiki.archlinux.org/title/File_permissions_and_attributes#Numeric_method
+find "$@" -type d -execdir chmod 755 -- '{}' \+
+find "$@" -type f -execdir chmod 644 -- '{}' \+
diff --git a/curlqb b/curlqb
new file mode 100755
index 0000000..d2851cd
--- /dev/null
+++ b/curlqb
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+# need --no-clobber if don't want overwrite when same name
+# if do this also need change .py.1 to .py else qbt will not accept
+# also if a.py and a_1.py, qbt will not accept the latter, maybe need to change some .py codes inside
+# now, I choose to let three files to be overwrited, those are "with categories" .py files that overwrite without categories .py files, which is what I want so I don't use --no-clobber
+curl -s 'https://github.com/qbittorrent/search-plugins/wiki/Unofficial-search-plugins' | awk -F'"' '
+/user-content-plugins-for-private-sites/ {exit}
+/\.py/ {
+ url=$2
+ getline
+ getline
+ getline
+ if($0 !~ /❗|✖/)
+ print url
+}
+' | xargs curl -s -Z -L --remote-name-all --create-dirs --output-dir "$1" --
+
+# an alternative awk command:
+#awk -F'"' '
+#/require an account/ {exit}
+#/\.py/ {
+# url=$2
+# line=NR
+#}
+#url && NR==line+3 && !/❗|✖/ {print url}
+#'
diff --git a/dateft b/dateft
new file mode 100755
index 0000000..b317474
--- /dev/null
+++ b/dateft
@@ -0,0 +1,29 @@
+#!/bin/sh
+# DATE From To
+
+while getopts cfF:t:T: opt; do
+ case $opt in
+ c) tz_from="Asia/Shanghai";;
+ f) tz_from="$(tzselect)";;
+ F) tz_from="$OPTARG";;
+ # one extra ',' at the end will not let `for tz in ...` loop one extra time?
+ t) for i in $(seq "$OPTARG"); do
+ tz_to="$(tzselect),$tz_to"
+ done;;
+ T) tz_to="$OPTARG,$tz_to";;
+ \?) exit 1;;
+ esac
+done
+shift $((OPTIND-1))
+
+time_from="TZ=\"${tz_from:-$(readlink /etc/localtime | sed 's#.*/\(.*/.*\)$#\1#')}\" ${1:-now}"
+
+date -d "$time_from"
+TZ="Asia/Shanghai" date -d "$time_from"
+date -d "$time_from" -u
+date -d "$time_from" +%s
+[ "$tz_from" ] && [ "$tz_from" != "Asia/Shanghai" ] && TZ="$tz_from" date -d "$time_from"
+IFS=','
+for tz in $tz_to; do
+ TZ="$tz" date -d "$time_from"
+done
diff --git a/dirnameall b/dirnameall
new file mode 100755
index 0000000..befd347
--- /dev/null
+++ b/dirnameall
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+while read -r line; do
+ if [ "$paths" ]; then
+ paths="$paths
+$line"
+ else
+ paths="$line"
+ fi
+done
+
+dirs="$paths"
+while [ "$dirs" != '.' ]; do
+ [ "$dirs" ] && paths="$paths
+$dirs"
+ dirs="$(echo "$dirs" | tr '\n' '\0' | xargs -0 dirname | awk '!a[$0]++')"
+done
+
+echo "$paths" | awk '!a[$0]++' | grep -v '^\.$'
diff --git a/gita b/gita
new file mode 100755
index 0000000..ee00306
--- /dev/null
+++ b/gita
@@ -0,0 +1,17 @@
+#!/bin/sh
+# note message string must come after options
+
+cmd=git
+
+while getopts ls f; do
+ case $f in
+ l|s) cmd="cfg -$f";;
+ \?) exit 1;;
+ esac
+done
+shift $((OPTIND-1))
+
+mes="${1:-update}"
+
+$cmd commit --all -m "$mes"
+$cmd push
diff --git a/gitfork b/gitfork
new file mode 100755
index 0000000..9736c4c
--- /dev/null
+++ b/gitfork
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+git clone "$1"
+cd "$(basename "$1" .git)" || exit
+git remote add upstream "$2"
+if ! git checkout fly; then
+ git branch fly
+ git checkout fly
+ git push --set-upstream origin fly
+fi
diff --git a/gitmetap b/gitmetap
new file mode 100755
index 0000000..c058986
--- /dev/null
+++ b/gitmetap
@@ -0,0 +1,17 @@
+#!/bin/sh
+# GIT META Print
+
+# -rw-r--r-- == binary 110100100 == octal 644
+# https://stackoverflow.com/a/1796009
+$1 ls-tree -r --name-only --full-tree HEAD | dirnameall | awk -v a="$2/" '{printf("%s%s\n",a,$0)}' | tr '\n' '\0' | xargs -0 ls -ldA -- | awk '{
+ k=0
+ for(i=0;i<=8;i++)
+ k+=((substr($1,i+2,1)~/[rwx]/)*2^(8-i))
+ if(k) {
+ for(i=10;$i && $i!="->";i++)
+ $9=$9" "$i
+ printf("%0o %s %s %s\n",k,$3,$4,$9)
+ }
+}' > "$3"
+
+#$1 ls-tree -r --name-only --full-tree HEAD | awk -v a="$2/" '{printf("%s%s\n",a,$0)}' | tr '\n' '\0' | xargs -0 ls -ldA -- | awk '{k=0;for(i=0;i<=8;i++)k+=((substr($1,i+2,1)~/[rwx]/)*2^(8-i));if(k){for(i=10;$i && $i!="->";i++)$9=$9" "$i;printf("%0o %s %s %s\n",k,$3,$4,$9)}}' > "$3"
diff --git a/gitmetar b/gitmetar
new file mode 100755
index 0000000..1bfdc15
--- /dev/null
+++ b/gitmetar
@@ -0,0 +1,7 @@
+#!/bin/sh
+# GIT META Read
+
+while read -r mod user group path; do
+ chown -hc "$user:$group" -- "$path"
+ [ "$mod" -ne 777 ] && chmod -c "$mod" -- "$path"
+done < "$1"
diff --git a/gitpu b/gitpu
new file mode 100755
index 0000000..5453fae
--- /dev/null
+++ b/gitpu
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+if [ -z "$1" ]; then
+ git checkout master
+ git pull upstream master
+ git push
+ git checkout fly
+ git merge --no-edit master
+ git push
+else
+ for dir; do
+ git -C "$dir" checkout master
+ git -C "$dir" pull upstream master
+ git -C "$dir" push
+ git -C "$dir" checkout fly
+ git -C "$dir" merge --no-edit master
+ git -C "$dir" push
+ done
+fi
diff --git a/grrc b/grrc
new file mode 100755
index 0000000..66a7200
--- /dev/null
+++ b/grrc
@@ -0,0 +1,4 @@
+#!/bin/sh
+# GRep -R Code
+
+[ "$1" ] && find "$HOME/archive/programs/public_archive_codes" "$HOME/archive/programs/private_archive_codes" "$HOME/archive/programs/me106_proj_fall2021" "$HOME/archive/programs/car_job/av_dev" "$HOME/archive/programs/VisualDimension" "$XDG_DOCUMENTS_DIR/notes" -mindepth 1 -maxdepth 1 -path "*/\.git" -prune -o -type d -print0 2>/dev/null | xargs -0 grep -s --color=always -iIR "$@" "$HOME/.local/bin" "$HOME/.bashrc" "$HOME/.profile" "$HOME/.xinitrc" "$HOME/programs/suckless/dwm_fly/config.def.h" "$XDG_CONFIG_HOME/nsxiv/exec/key-handler" | "$PAGER"
diff --git a/il b/il
new file mode 100755
index 0000000..7c75a71
--- /dev/null
+++ b/il
@@ -0,0 +1,6 @@
+#!/bin/sh
+# InterpoLation
+
+# x=$1, xa=$2, xb=$3, ya=$4, yb=$5
+# https://en.wikipedia.org/wiki/Interpolation#Linear_interpolation
+echo "scale=4;$4+($5-$4)*($1-$2)/($3-$2)" | bc
diff --git a/lastarg b/lastarg
new file mode 100755
index 0000000..b52afcd
--- /dev/null
+++ b/lastarg
@@ -0,0 +1,5 @@
+#!/bin/sh
+# usage: lastarg "$@"
+
+shift $(($# - 1))
+echo "$1"
diff --git a/loop b/loop
new file mode 100755
index 0000000..6a57826
--- /dev/null
+++ b/loop
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+while getopts t: opt; do
+ case $opt in
+ t) time="$OPTARG";;
+ \?) exit 1;;
+ esac
+done
+shift $((OPTIND-1))
+
+while :; do
+ # suggested by https://github.com/koalaman/shellcheck/wiki/SC2294
+ "$@"
+ sleep "${time:-1}"
+done
diff --git a/lsp b/lsp
new file mode 100755
index 0000000..4e2caa0
--- /dev/null
+++ b/lsp
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+loop ssh "${1:-pp}"
diff --git a/mll b/mll
new file mode 100755
index 0000000..9f7d5df
--- /dev/null
+++ b/mll
@@ -0,0 +1,6 @@
+#!/bin/sh
+# Map Latitude Longitude
+
+# https://help.openstreetmap.org/questions/9669/jumping-to-a-specific-set-of-coordinates-on-the-map
+# another way is to manually search xx.xxxxx,xx.xxxxx
+o "$BROWSER" "https://www.openstreetmap.org/?mlat=$1&mlon=$2&zoom=5"
diff --git a/mmi b/mmi
new file mode 100755
index 0000000..350fe50
--- /dev/null
+++ b/mmi
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+mi () {
+ make
+ sudo make install
+}
+
+origin="$PWD"
+cmd='mi'
+
+while getopts q opt; do
+ case $opt in
+ q) cmd='qmake6;mi';;
+ \?) exit 1;;
+ esac
+done
+shift $((OPTIND-1))
+
+if [ -z "$1" ]; then
+ eval "$cmd"
+else
+ for dir; do
+ cd "$dir" || exit
+ eval "$cmd"
+ cd "$origin" || exit
+ done
+fi
diff --git a/mpra b/mpra
new file mode 100755
index 0000000..0801e55
--- /dev/null
+++ b/mpra
@@ -0,0 +1,44 @@
+#!/bin/sh
+# MakePkg Repo-Add
+
+fn () {
+ if ! { [ -f PKGBUILD ] || [ -h PKGBUILD ];}; then
+ exit
+ fi
+ find . -maxdepth 1 -type f -name "*.pkg.tar.$ext*" -delete
+ makepkg --sign -sf
+ newpkg="$(find . -maxdepth 1 -type f -name "*.pkg.tar.$ext")"
+ [ -d ../repo ] || mkdir ../repo
+ mv "$newpkg" "$newpkg.sig" ../repo
+ # need manually repo-add new database for first time initialization
+ repo-add -s -v -R "$(find ../repo -maxdepth 1 -type f -name '*.db.tar.gz')" "../repo/$newpkg"
+ # seems no need to delete *.old and *.old.sig, see https://mirror.fcix.net/archlinux/core/os/x86_64/ it do include *.old
+ #find ../repo -maxdepth 1 -type f \( -name '*.old' -o -name '*.old.sig' \) -delete
+}
+
+ext=zst
+copy_any=
+
+while getopts ac opt; do
+ case $opt in
+ # arch linux arm still using .xz instead of .zst as package compression format
+ a) ext=xz;;
+ # copy arch linux fly-any repo
+ c) copy_any=1;;
+ \?) exit 1;;
+ esac
+done
+shift $((OPTIND-1))
+
+if [ $# -eq 0 ]; then
+ fn
+else
+ for dir; do
+ cd -- "$(realpath -- "$dir")" || exit
+ fn
+ done
+fi
+
+[ "$copy_any" ] && sudo rsync -vPrlt --delete ../repo/ /srv/http/mirrors/archlinux/fly/os/any
+
+upd -p
diff --git a/mpva b/mpva
new file mode 100755
index 0000000..d80c9f3
--- /dev/null
+++ b/mpva
@@ -0,0 +1,17 @@
+#!/bin/sh
+# MPV Audio
+
+# fzf has --read0, maybe useful
+# use --loop-file for single file, better performance maybe
+# fzf --scheme=path for better fzf result when searching path, like the old time:
+# https://github.com/junegunn/fzf/commit/6fb41a202a97ad3f2437f6e5aee8890268560412
+
+if [ $# -eq 0 ]; then
+ find "$XDG_MUSIC_DIR" | fzf -m --print0 --scheme=path
+fi | xargs -0 sh -c '
+if [ $# -eq 1 ] && ! [ -d "$1" ]; then
+ mpv --af= --loop-file=inf --video=no "$1"
+else
+ mpv --af= --shuffle --loop-playlist=inf --video=no "$@"
+fi
+' shell "$@"
diff --git a/mpvy b/mpvy
new file mode 100755
index 0000000..1cf17a7
--- /dev/null
+++ b/mpvy
@@ -0,0 +1,44 @@
+#!/bin/sh
+# MPV Yank/Youtube videos
+# references:
+# https://www.rockyourcode.com/til-how-to-watch-youtube-videos-with-mpv-and-keyboard-shortcuts/
+
+fps=30
+height=$SCR_HEIGHT
+url="$(xsel -ob)"
+flag=s
+
+# option f and h may do nothing if redownload? since same filename exist. yt-dlp won't download same file even without --auto-file-renameing=false. how improve? pass argument to aria2c?
+while getopts Aabd:f:h:su: opt; do
+ case $opt in
+ # s: streaming, a: aria2c then mpv, A: aria2c
+ A|a|s) flag=$opt;;
+ b) format='bestvideo+bestaudio/best';;
+ d) download_dir="$OPTARG";;
+ f) fps="$OPTARG";;
+ h) height="$OPTARG";;
+ u) url="$OPTARG";;
+ \?) exit 1;;
+ esac
+done
+if [ -z "$format" ]; then
+ #vformat="[height<=?$height][fps<=?$fps][vcodec!^=?vp9][vcodec!^=?av01]"
+ vformat="[height<=?$height][fps<=?$fps][vcodec!^=?av01]"
+ # usually get .mp4 video + .webm audio on youtube, yt-dlp needs to merge them to .mkv
+ # it used to cause problem, but I forget
+ format="bestvideo$vformat+bestaudio/best$vformat"
+fi
+
+case $flag in
+ # here if use --write-sub, mpv doesn't recognize subtitles?
+ # --embed-subs is a little bit better, but still worse then direct streaming
+ # --sponsorblock-remove will make audio/video goes out of sync, need --force-keyframes-at-cuts which need re-encode which is slow, more see comments at the bottom of https://github.com/yt-dlp/yt-dlp/issues/871
+ # another way is using mpv-sponsorblock-minimal-git for streaming and sponsorblock-mpv-local for local videos
+ A) yt-dlp -f "$format" --embed-subs -P "${download_dir:-"$XDG_DOWNLOAD_DIR/mpvy/"}" --sponsorblock-remove default --sponsorblock-mark default "$url";;
+ a) yt-dlp -f "$format" --embed-subs -P "${download_dir:-"$XDG_DOWNLOAD_DIR/mpvy/"}" --sponsorblock-remove default --sponsorblock-mark default "$url" --exec 'mpv --fs --speed=2';;
+ s) mpv --ytdl-format="$format" --ytdl-raw-options='write-sub=' --fs --speed=2 "$url";;
+esac
+# not sure if this is the best practice, but it seems working ;)
+status=$?
+[ $status -ne 0 ] && notify-send 'mpvy failed'
+exit $status
diff --git a/mvln b/mvln
new file mode 100755
index 0000000..54cef54
--- /dev/null
+++ b/mvln
@@ -0,0 +1,27 @@
+#!/bin/sh
+# edge cases give me headache
+
+lns () {
+ # prevent `mvln file1 file1` or `mvln dir1/file1 dir1/`
+ # which means `ln -s samename samename` or `ln -s dir/file dir/`
+ # both $1 and $2 here are realpath
+ [ "$1" != "$2" ] && ln -s -- "$1" "$2"
+}
+
+mv -i -- "$@"
+# consider `mvln file1 dir/file2`
+if [ $# -eq 2 ] && ! [ -d "$2" ]; then
+ # use realpath here
+ lns "$(realpath "$2")" "$(realpath "$1")"
+else
+ dir="$(realpath -- "$(lastarg "$@")")"
+ # steal from https://unix.stackexchange.com/a/353833/459013
+ while [ $# -gt 1 ]; do
+ to="$(realpath -- "$1")"
+ # prevent `mvln dir1/ dir1/`
+ if [ "$dir" != "$to" ]; then
+ lns "$dir/$(basename "$1")" "$to"
+ fi
+ shift
+ done
+fi
diff --git a/mvtr b/mvtr
new file mode 100755
index 0000000..28eebf0
--- /dev/null
+++ b/mvtr
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# can use ls pipe to sed pipe to bash, similar to eval? see comment at link:
+# link also show perl-rename approach
+# https://linuxconfig.org/rename-all-files-from-uppercase-to-lowercase-characters
+# if only change ' ' to '_' `rename` might be sufficient, for upper to lower case might need perl-rename if want concise
+
+# ./_filename will be renamed ./filename, not what I want, need improve
+# -exec can't replace -execdir here, can write a -exec version
+
+find "$@" -depth -execdir sh -c 'dest="$(echo "$1" | tr -d "\047" | sed -E -e "s/([[:lower:]])([[:upper:]])/\1_\2/g" | tr "[:upper:] " "[:lower:]_" | tr -s "[:punct:]" | sed -E -e "s#/-#/#g" -e "s/_([[:punct:]])/\1/g" -e "s/([[:punct:]])_/\1/g" | tr -s "[:punct:]")"; [ -e "$dest" ] || mv -v -- "$1" "$dest"' shell '{}' \;
diff --git a/mvtu b/mvtu
new file mode 100755
index 0000000..6160507
--- /dev/null
+++ b/mvtu
@@ -0,0 +1,13 @@
+#!/bin/sh
+# MV Time-Uuid
+
+find "$@" -type f -execdir sh -c '
+ file="$(basename "$1")"
+ ext="${file##*.}"
+ if [ "$ext" != "$file" ]; then
+ dest="$(time-uuid).$ext"
+ else
+ dest="$(time-uuid)"
+ fi
+ [ -e "dest" ] || mv -v -- "$1" "$dest"
+' shell '{}' \;
diff --git a/news b/news
new file mode 100755
index 0000000..e0d2ffa
--- /dev/null
+++ b/news
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+daily () {
+ # mail.yahoo.com/d/folders/6 is spam folder
+ o "$BROWSER" https://github.com/notifications https://mail.google.com 'https://mail.google.com/mail/u/0/#spam' https://mail.yahoo.com https://mail.yahoo.com/d/folders/6 https://en.wikipedia.org/wiki/Portal:Current_events
+ # alacritty --hold must be before -e
+ # full window: -w156, am and pm in one line: -w114
+ o alacritty --hold -e rem -cu+2 -@ -w114
+ o alacritty --hold -e wtr
+ o alacritty -e newsboat
+ o alacritty --hold -e pass practice_password0
+}
+
+monthly () {
+ o "$BROWSER" https://smtp.cheogram.com/ http://download.huzheng.org
+ o alacritty --hold -e rate
+ # Show 3 months' remind. I use 3 months because it is better to know I20 deadline 3 months earlier so I have 2 months to prepare the money for extension.
+ # (2*31+30+6)/7=14. Consider month 1 day 1 is on Sunday and make sure month 3 day 31 is shown. Tested with `rem -cu+14 -@ -w114 2025-03-01`
+ o alacritty --hold -e sh -c 'rem -cu+14 -@ -w114 | $PAGER'
+}
+
+if [ $# -eq 0 ]; then
+ daily
+else
+ while getopts m opt; do
+ case $opt in
+ m) monthly;;
+ \?) exit 1;;
+ esac
+ done
+fi
diff --git a/o b/o
new file mode 100755
index 0000000..8fb066c
--- /dev/null
+++ b/o
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+# useful links
+# https://stackoverflow.com/questions/3430330/best-way-to-make-a-shell-script-daemon
+# https://serverfault.com/questions/117152/do-background-processes-get-a-sighup-when-logging-off
+# https://wiki.archlinux.org/title/default_applications
+
+# I don't care about errors, I don't want to handle errors, just shut up please.
+# nohup seems not necessary if don't care about daemon SIGHUP requirement
+
+# when close a shell script's stdout or stderr with `>&-` or `2>&-`, `xsel -ib` in that script has no effect
+# https://github.com/kfish/xsel/issues/43
+# using `>&-` or `2>&-` doesn't completely close mpv's output when run sth. like `o mpv file.mkv`
+# base on above observations, I choose to use `>/dev/null 2>&1` instead
+
+# need ; before } when it is in the same line as { ? https://www.shellcheck.net/wiki/SC1056
+
+if [ $# -eq 1 ] && [ -e "$1" ] && { ! [ -x "$1" ] || [ -d "$1" ];}; then
+ case "$1" in
+ # libreoffice, please don't let firefox eat your shit
+ *.docx|*.pptx) cmd=libreoffice;;
+ *) cmd=xdg-open;;
+ esac
+ nohup "$cmd" "$1" 0<&- >/dev/null 2>&1 &
+else
+ nohup "$@" 0<&- >/dev/null 2>&1 &
+fi
diff --git a/orgext b/orgext
new file mode 100755
index 0000000..0143e62
--- /dev/null
+++ b/orgext
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+outdir () {
+ find . -type f -execdir mv -t "$PWD" -- '{}' \+
+ find . -mindepth 1 -maxdepth 1 -type d -execdir rmdir -- '{}' \+
+}
+
+indir () {
+ # https://stackoverflow.com/questions/1842254/how-can-i-find-all-of-the-distinct-file-extensions-in-a-folder-hierarchy
+ find . -maxdepth 1 -type f | awk -F. '!a[$NF]++{print $NF}' | xargs mkdir --
+ find . -mindepth 1 -maxdepth 1 -type d -execdir basename -az -- '{}' \+ | xargs -0 -I _ find . -maxdepth 1 -type f -name '*._' -execdir mv -t '_' -- '{}' \+
+}
+
+case "$1" in
+ '-o') outdir;;
+ '-i') indir;;
+ *) outdir; indir;;
+esac
diff --git a/pa b/pa
new file mode 100755
index 0000000..86ae4e5
--- /dev/null
+++ b/pa
@@ -0,0 +1,8 @@
+#!/bin/sh
+# Ping Alarm
+
+while ! ping -w5 "$1"; do
+ sleep 5
+done
+notify-send "$1 on"
+bell
diff --git a/pq b/pq
new file mode 100755
index 0000000..bad9c35
--- /dev/null
+++ b/pq
@@ -0,0 +1,13 @@
+#!/bin/sh
+# Pacman Query, to manually determine remove the package or not
+
+[ "$1" ] && {
+ #sed -n '/^Depends On/,/^Conflicts With/{/^Conflicts With/!p}; /^Description\|^URL\|^Groups\|^Installed Size\|^Install Reason/p'
+ pacman -Qi "$1" | awk '/^Groups/{f=1} /^Conflicts With/{f=0} f||/^Description|^URL|^Installed Size|^Install Reason/'
+ printf '\n'
+ pacman -Ql "$1" | grep '/bin/[^$]'
+ printf '\n'
+ pactree -r "$1"
+ printf '\n'
+ grrc "$1"
+} | "$PAGER"
diff --git a/px b/px
new file mode 100755
index 0000000..1b4e849
--- /dev/null
+++ b/px
@@ -0,0 +1,10 @@
+#!/bin/sh
+# Printf Xsel
+
+if [ $# -eq 0 ]; then
+ /usr/bin/printf '%q' "$PWD"
+else
+ for dir; do
+ /usr/bin/printf '%q ' "$(realpath -- "$dir")"
+ done
+fi | xsel -ib
diff --git a/qg b/qg
new file mode 100755
index 0000000..dde5190
--- /dev/null
+++ b/qg
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+# more resources see comments in my script qw
+# https://guix.gnu.org/manual/en/html_node/Running-Guix-in-a-VM.html
+# `-enable-kvm` same as `-accel kvm`, see archwiki
+qemu-system-x86_64 \
+ -accel kvm \
+ -cpu host \
+ -device virtio-blk,drive=myhd \
+ -display gtk,zoom-to-fit=on \
+ -drive if=none,file="$XDG_DOWNLOAD_DIR/qemu/guix.img",format=qcow2,id=myhd \
+ -m 8G \
+ -nic user,model=virtio-net-pci,hostfwd=::53684-:22 \
+ -smp 2,sockets=1,cores=1,threads=2 \
+ -usb -device usb-tablet
diff --git a/qw b/qw
new file mode 100755
index 0000000..e77b88f
--- /dev/null
+++ b/qw
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+# For better performance, it needs CPU-pinning with `taskset`, GPU pass-through, and other more tweaks
+# https://github.com/cardi/qemu-windows-10
+# https://wiki.archlinux.org/title/QEMU
+## https://wiki.archlinux.org/title/QEMU#Mouse_integration
+# https://qemu-project.gitlab.io/qemu/system/devices/usb.html
+qemu-system-x86_64 \
+ -accel kvm \
+ -cpu host,hv_relaxed,hv_spinlocks=0x1fff,hv_vapic,hv_time \
+ -display gtk,zoom-to-fit=on \
+ -drive file="$XDG_DOWNLOAD_DIR/qemu/win10.img",format=qcow2 \
+ -m 8G \
+ -nic user,hostfwd=::53683-:22 \
+ -smp 2,sockets=1,cores=1,threads=2 \
+ -usb -device usb-tablet
diff --git a/rate b/rate
new file mode 100755
index 0000000..1625df6
--- /dev/null
+++ b/rate
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+while getopts f:t: opt; do
+ case $opt in
+ f) from="$OPTARG";;
+ t) to="$(echo "$OPTARG" | tr '[:lower:]' '[:upper:]')";;
+ \?) exit 1;;
+ esac
+done
+# https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-exchange-rates
+curl -s "https://api.coinbase.com/v2/exchange-rates?currency=${from:-xmr}" | jq -r ".data.rates.${to:-USD}"
diff --git a/reco b/reco
new file mode 100755
index 0000000..7ee726d
--- /dev/null
+++ b/reco
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+# useful urls:
+# https://github.com/LukeSmithxyz/voidrice/blob/master/.local/bin/dmenurecord
+# https://wiki.archlinux.org/title/FFmpeg#Screen_capture
+# https://trac.ffmpeg.org/wiki/Capture/Desktop
+
+infofile="/tmp/recoinfo"
+recodir="$XDG_VIDEOS_DIR/recordings/"
+tmpdir="$recodir/tmp/"
+mkdir -p "$recodir" "$tmpdir"
+
+if [ -e "$infofile" ]; then
+ read -r pid tmpfile < "$infofile"
+ kill "$pid"
+ notify-send 'finish recording, start converting'
+ ffmpeg -i "$tmpfile" "$recodir/$(time-uuid).mkv"
+ notify-send 'finish converting'
+ rm "$tmpfile" "$infofile"
+else
+ tmpfile="$tmpdir/$(time-uuid).mkv"
+ notify-send 'prepare recording'
+ # arch wiki way, no audio, less cpu use during capturing (fast?), large file size, need convert afterward
+ xrectsel '%w %h %x %y' | xargs sh -c 'ffmpeg -y -loglevel quiet -f x11grab -framerate 25 -s "$2x$3" -i "$DISPLAY+$4,$5" -c:v ffvhuff "$1" & echo $!' shell "$tmpfile" | xargs -I {} printf '%s\t%s' '{}' "$tmpfile" > "$infofile"
+ # another way to get subshell ffmpeg child pid
+ #xrectsel '%w %h %x %y' | xargs sh -c 'ffmpeg -y -f x11grab -framerate 25 -s "$2x$3" -i "$DISPLAY+$4,$5" -c:v ffvhuff "$1"' shell "$tmpfile" &
+ #printf '%s\t%s' "$(ps -o pid= --ppid $!)" "$tmpfile" > "$infofile"
+fi
diff --git a/rfp b/rfp
new file mode 100755
index 0000000..c1a3e1f
--- /dev/null
+++ b/rfp
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+if grep -q '^//user_pref("privacy.resistFingerprinting", false);$' "$HOME/.mozilla/firefox/xxxxxxxx.fly/user-overrides.js"; then
+ sed -i 's#^//\(user_pref("privacy.resistFingerprinting", false);\)$#\1#' "$HOME/.mozilla/firefox/xxxxxxxx.fly/user-overrides.js"
+ notify-send -u critical 'RFP disabled'
+else
+ sed -i 's#^\(user_pref("privacy.resistFingerprinting", false);\)$#//\1#' "$HOME/.mozilla/firefox/xxxxxxxx.fly/user-overrides.js"
+ notify-send 'RFP enabled'
+fi
+upd -j
+o "$BROWSER"
diff --git a/sbar b/sbar
new file mode 100755
index 0000000..392b65a
--- /dev/null
+++ b/sbar
@@ -0,0 +1,77 @@
+#!/bin/sh
+# modified from pystardust, GPLv3 license: https://github.com/pystardust/sbar
+
+# INIT
+sec=0
+
+# MODULES
+update_time () {
+ time="$(date '+%a %m/%d %H:%M') $(TZ=Asia/Shanghai date '+/%d %H:') $(date -u '+/%d %H:')"
+}
+
+#update_cap () {
+# cap="$(if xset q | grep -q "Caps Lock: *on"; then echo A; else echo a; fi)"
+#}
+
+update_net () {
+ net="$(if nmcli -t --fields type,state device | grep -q '^\(ethernet\|wifi\):connected$'; then echo 1; else echo 0; fi)"
+ nm_device_state="$(nmcli -t --fields device,state device)"
+ vpn="$(
+ if echo "$nm_device_state" | grep -q '^wg_ka:connected$'; then
+ echo K
+ elif echo "$nm_device_state" | grep -q '^wg_studio:connected$'; then
+ echo S
+ else
+ echo 0
+ fi
+ )"
+}
+
+update_vol () {
+ # $(NF-1) for both alsa and pulseaudio
+ vol="$(amixer get Master | awk -F'[][]' 'END{printf("%d %s",($(NF-1)=="on")?1:0,$2)}')"
+}
+
+update_mic () {
+ # $(NF-1) for both alsa and pulseaudio
+ mic="$(amixer get Capture | awk -F '[][]' 'END{print ($(NF-1)=="on")?1:0}')"
+}
+
+update_bat () {
+ bat="$(cat /sys/class/power_supply/BAT0/capacity)%"
+}
+
+update_gpu () {
+ gpu="$(envycontrol -q | awk 'END{print toupper(substr($NF,0,1))}')"
+}
+
+display () {
+ xsetroot -name "$time | N $net V $vpn | M $vol C $mic | $gpu | $bat"
+}
+
+# modules that don't update on their own need to be run at the start for getting their initial value
+update_net
+update_vol
+update_mic
+update_gpu
+
+# SIGNALLING
+# trap "<function>;display" "RTMIN+n"
+trap "update_mic;display" "RTMIN"
+trap "update_vol;display" "RTMIN+1"
+# xev can't read my toggle internet keyboard key, don't know what key to use in sxhkd to send signal
+trap "update_net;display" "RTMIN+2"
+# to update it from external commands
+## kill -m $(pidof -x sbar)
+# where m = 34 + n
+
+while :; do
+ sleep 1 &
+ wait
+ [ $((sec % 5 )) -eq 0 ] && update_time # update time every 5 seconds
+ [ $((sec % 60)) -eq 0 ] && update_net
+ [ $((sec % 60)) -eq 0 ] && update_bat
+ # how often the display updates ( 5 seconds )
+ [ $((sec % 5 )) -eq 0 ] && display
+ sec=$((sec + 1))
+done
diff --git a/ta b/ta
new file mode 100755
index 0000000..ae386c1
--- /dev/null
+++ b/ta
@@ -0,0 +1,5 @@
+#!/bin/sh
+# TIme Alarm
+
+time -p "$@"
+o alarm 0 'Command Finished' "$(/usr/bin/printf '%q ' "$@")"
diff --git a/time-uuid b/time-uuid
new file mode 100755
index 0000000..bdaf4b3
--- /dev/null
+++ b/time-uuid
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# echo current nanosecond since epoch and alpha-numerically ordered UUID
+# https://stackoverflow.com/questions/28681650/generate-alpha-numerically-ordered-uuids-over-time?noredirect=1&lq=1
+# https://askubuntu.com/questions/342842/what-does-this-command-mean-awk-f-print-4
+echo "$(date '+%s-%N')-$(uuidgen -t | awk -F- '{OFS="-"; print $3,$2,$1,$4,$5}')"
diff --git a/topa b/topa
new file mode 100755
index 0000000..3252997
--- /dev/null
+++ b/topa
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+o alacritty -e htop
+#o alacritty -e radeontop -c
+o alacritty -e iotop
+o alacritty -e nethogs
+o alacritty -e intel_gpu_top
+o alacritty -e nvtop
diff --git a/vinfo b/vinfo
new file mode 100755
index 0000000..190de19
--- /dev/null
+++ b/vinfo
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+# steal from https://github.com/HiPhish/info.vim
+"$EDITOR" -RM +"Info $1 $2" +only
diff --git a/wh b/wh
new file mode 100755
index 0000000..d20f0de
--- /dev/null
+++ b/wh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# blue, see `man terminfo`
+setaf="$(tput setaf 4)"
+sgr0="$(tput sgr0)"
+
+# dash `command -V "$@"` will only output first command's type, same as `type`, but different than posix specification? so not use here
+for cmd in type whatis whereis which "pacman -Qo --color always"; do
+ printf '\n%s\n%s\n' "$setaf$cmd $*$sgr0" "$($cmd "$@" 2>&1)"
+ #printf '\n\033[0;34m%s\033[0m\n%s\n' "$setaf$cmd $*$sgr0" "$($cmd "$@" 2>&1)"
+done | "$PAGER"
diff --git a/wtr b/wtr
new file mode 100755
index 0000000..c9907d9
--- /dev/null
+++ b/wtr
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+# https://github.com/open-meteo/open-meteo
+i=0
+curl -s -G -d "latitude=${1:-37.34}" -d "longitude=${2:--121.89}" -d 'daily=weathercode,temperature_2m_max,temperature_2m_min,sunrise,sunset' -d 'timezone=auto' 'https://api.open-meteo.com/v1/forecast' | jq -r '[.daily|.time, .weathercode, .temperature_2m_max, .temperature_2m_min, .sunrise, .sunset]|transpose|.[]|@tsv' | while read -r time code max min sunrise sunset; do
+ # https://open-meteo.com/en/docs
+ case "$code" in
+ 0) code='clear sky';;
+ 1) code='mainly clear';;
+ 2) code='partly cloudy';;
+ 3) code=overcast;;
+ 45) code=fog;;
+ 48) code='depositing rime fog';;
+ 51) code='light drizzle';;
+ 53) code='moderate drizzle';;
+ 55) code='dense drizzle';;
+ 56) code='light freezing drizzle';;
+ 57) code='dense freezing drizzle';;
+ 61) code='slight rain';;
+ 63) code='moderate rain';;
+ 65) code='heavy rain';;
+ 66) code='light freeze rain';;
+ 67) code='heavy freeze rain';;
+ 71) code='slight snow fall';;
+ 73) code='moderate snow fall';;
+ 75) code='heavy snow fall';;
+ 77) code='snow grains';;
+ 80) code='slight rain showers';;
+ 81) code='moderate rain showers';;
+ 82) code='violent rain showers';;
+ 85) code='slight snow showers';;
+ 86) code='heavy snow showers';;
+ 95) code='slight or moderate thunderstorm';;
+ 96) code='thunderstorm with slight hail';;
+ 99) code='thunderstorm with heavy hail';;
+ *) exit 1;;
+ esac
+ if [ "$i" -ne 1 ]; then
+ printf 'sunrise: %s | sunset: %s\n' "${sunrise#*T}" "${sunset#*T}"
+ i=1
+ fi
+ printf '%s\t%s\t%s\t%s\n' "${time#*-}" "$max" "$min" "$code"
+done
diff --git a/xmq b/xmq
new file mode 100755
index 0000000..83eca0f
--- /dev/null
+++ b/xmq
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+xdg-mime query filetype "$1" | tee /dev/tty | xargs xdg-mime query default